2016-08-19 2 views
2

Я хочу манипулировать экземпляром делегатом, который является свойством самого класса. Параметр делегата должен всегда быть самим экземпляром (даже в производных классах!).Использовать производный тип класса как параметр общего действия базового класса

См. Код ниже. Я знаю, что код не компилируется, потому что мне приходится бросать автомобиль1 на автомобиль, я ищу решение без кастинга.

Код

static void Main(string[] args) 
{ 
    var car = new Car(); 
    car.VehicleManipulator = car1 => car1.SomeInt++; 
    car.ManipulateVehicle(); 

    Console.WriteLine("end"); 
    Console.ReadLine(); 
} 

internal class Vehicle 
{ 
    public Action<Vehicle> VehicleManipulator { get; set; } 

    public void ManipulateVehicle() 
    { 
     this.VehicleManipulator(this); 
    } 
} 

internal class Car : Vehicle 
{ 
    public int SomeInt { get; set; } 
} 

EDIT: Измененный код!

Мой вопрос в том, есть ли хорошее решение для обработки всего этого только в базовом классе, но в действии я хочу использовать производные классы без кастинга.

+0

Где проблема? Вы можете использовать метод [virtual] (http://stackoverflow.com/q/8309419/1997232), который весь унаследованный класс переопределяет, если это проблема. – Sinatr

+0

Действие Car.VehicleManipulator равно null, вы никогда не назначали его, делаете его виртуальным, а компилятор будет искать реализацию в производных классах –

+0

@ A.T. напротив * свойство * присваивается, но метод использует свойство * базового класса *. Это не касается нулей, это о наследовании –

ответ

2

Если вы хотите, чтобы избежать отливки, сделать Vehicle родовым как:

class Vehicle<T> where T : Vehicle { 
    Action<T> ManipulateVehicle { get; set; } 
} 

class Car : Vehicle<Car> { 
    int SomeInt { get; set; } 
} 

Это выглядит немного странно, но это означает, что если у вас есть экземпляр автомобиля, то манипулятор работает на автомобилях, и если у вас есть грузовик, он работает на грузовиках и так далее. Возможно, транспортное средство должно быть абстрактным.

4

Вы близко. Причина, по которой вы получаете NullReferenceException для этой линии car.ManipulateVehicle();, заключается в том, что действие VehicleManipulator равно null.

enter image description here

И как вы видите VehicleManipulator свойство базового класса является нулевым.

Теперь, как это может быть null, если только выше линии вы терпите неудачу при назначении действий? Таким образом, проблема в том, что в вашем производном классе, автомобиле, у вас есть новый другой объект с именем VehicleManipulator, который скрывает базовый. Поэтому, когда вы назначаете car.VehicleManipulator, вы фактически присваиваете свойство в производном классе, а не в базовом классе.

Удалите это из производного класса у него получится.

Если, по причине того, что я еще не могу понять, вы хотите сохранить свойство в производном классе, то при выполнении назначения вы можете указать, что вы хотите назначить на базовый класс, как это:

enter image description here

+0

@Snowcrack - это прояснило, что происходит и помогает решить его? –

0

Просто удалите эту строку коды из класса автомобиля:

public Action<Car> VehicleManipulator { get; set; } 

ManipulateVehicle является методом базового класса и при вызове его ковшики с VehicleManipulator свойства базы (не производный) класса.

Добавление VehicleManipulator свойства производного класса скрывает основную собственность и когда назначено - базовая свойство имеет это значение по умолчанию из null следовательно NullReferenceException

Я также рекомендую, чтобы добавить ключевое слово abstract в Vehicle «s подписи, как это чистая абстракция.Никто не может создать только Vehicle без типа и т.д., только для автомобилей, грузовики, мотоциклы и т.д.

Таким образом, рабочий код может быть что-то вроде этого:

abstract internal class Vehicle 
{ 
    public virtual Action<Vehicle> VehicleManipulator { get; set; } 

    public void ManipulateVehicle() 
    { 
     this.VehicleManipulator(this); 
    } 
} 

internal class Car : Vehicle 
{ 
} 
Смежные вопросы