2013-04-02 2 views
0

У меня есть следующий абстрактный класс:Действие параметры делегата не совпадают с использованием реализован абстрактный класс

public abstract class BaseClass{ 
    public object contents { get; set; } 
    public Action<BaseClass> mutator; 
    public abstract void Initialise(); 
} 

Это будет использоваться несколько классов, которые будут переопределять метод Initialize, чтобы присвоить значение contents, который будет в свою очередь, мутируют с использованием делегата mutator в определенные моменты времени.

У меня есть следующий статический класс, причем каждый метод предназначен для использования в качестве mutator:

public static class Mutators{ 
    public static void VariantA(A inputObj){ 
     // inputObj.contents = something else 
    } 

    public static void VariantB(A inputObj) { } // etc. etc. 
} 

Я тогда класс А, который реализует BaseClass. Я пытаюсь назначить Mutators.VariantA делегату мутатора, но я не могу.

public class A : BaseClass{ 
    public A(){ 
     mutator = Mutators.VariantA; 
    } 

    public override void Initialise(){ 
     /* set the value of contents property here */ 
    } 
} 

В частности, я получаю следующее сообщение об ошибке: A method or delegate Mutators.VariantA (A)»параметры не совпадают Делегат System.Action<BaseClass>(BaseClass)' parameters (CS0123)

Я понимаю, что Mutators.VariantA(A) требует объект типа A, и действие было объявлено, чтобы принять вход типа BaseClass, однако как класс A реализует BaseClass Я думал, что смог бы это сделать?

Исходя из динамически типизированных языков, я имею трудное время схватившись с работой с типами таким образом :(

Есть ли способ, я могу указать на функцию с входом абстрактного типа в таким образом? Мне нужно, чтобы посмотреть на какой-то другой шаблон дизайна ли?

Благодаря

ответ

4

I understand that Mutators.VariantA(A) requires an object of type A, and the Action was declared to accept an input of type BaseClass, however as class A implements BaseClass I thought I would have been able to do this ?

Абсолютно нет.

Action<BaseClass> должен принимать любойBaseClass объект. Так, например, если ваш код был действительно, я мог бы написать: (. Где B еще один класс, производный от BaseClass)

Action<BaseClass> mutator = Mutators.VariantA; 
mutator.Invoke(new B()); 

Тот факт, что B происходит от BaseClass делает его действительным для вызов - но это не поможет вашему методу VariantA работать красиво.

Это не совсем понятно, почему у вас есть мутатор здесь - я сильно подозреваю, что вы должны абстрагироваться от его мутаций BaseClass. Я по-прежнему не следую тому, чего вы пытаетесь достичь, но этот шаблон дизайна не поможет вам добраться до безопасного типа.

Вы могли написать:

public abstract class BaseClass<T> where T : BaseClass<T> { 
    public object Contents { get; set; } 
    public Action<T> Mutator { get; set; } 
    public abstract void Initialise(); 
} 

...затем:

public class A : BaseClass<A> { 
    public A() { 
     Mutator = Mutators.VariantA; 
    } 
} 

... как тогда вы писали бы что-то, что может изменить значения «А». Но по моему опыту такое родовое гнездование становится действительно грязным, очень быстрым.

+0

'Jon Skeet' вы путь toooooo' Fast' лол – MethodMan

+0

Причина у меня есть мутатором является то, что я должен иметь возможность разрешить пользователю указывать, какую мутацию они хотели бы выполнять в классе, который содержит различные типы данных. Я также хочу иметь возможность разрешать настраиваемые функции мутаторов. Спасибо, что расчистил это для меня Джон. – Sherlock

1

Я использовал свой текущий пример и изменил метод подписи одного из классов на следующее, и она работает

public abstract class BaseClass 
    { 
     public object contents { get; set; } 
     public Action<BaseClass> mutator; 
     public abstract void Initialise(); 
    } 
    public static class Mutators 
    { 
     public static void VariantA(BaseClass baseClass) 
     { 
      // inputObj.contents = something else 
     } 

     public static void VariantB(A inputObj) { } // etc. etc. 
    } 
    public class A : BaseClass 
    { 
     public A() 
     { 
      mutator = Mutators.VariantA; 
     } 

     public override void Initialise() 
     { 
      /* set the value of contents property here */ 
     } 
    } 
Смежные вопросы