2012-01-24 3 views
0

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

BaseStepHandler<BaseStepDataModel> activator = (BaseStepHandler<BaseStepDataModel>)Activator.CreateInstance(....); 

Созданный экземпляр может быть всем дочерним элементом BaseStepDataModel.

BaseStepHandler<OneDataModel>
OR
BaseStepHandler<TwoDataModel>

OneDataModel и TwoDataModel расширяют BaseStepDataModel.

это исключение, которое я получаю:

Невозможно привести объект типа '.... GlobalOnBoardingStepOneHandler' для типа '.... BaseStepHandler`1 [.... BaseStepDataModel].

Это объявление, если GlobalOnBoardingStepOneHandler.

public class GlobalOnBoardingStepOneHandler : BaseStepHandler<GlobalOnBoardingStepOneDataModel>{} 
+2

Какой вопрос? –

+0

@JoachimIsaksson - см. Тему (я также добавил исключение) – SexyMF

+0

@JoachimIsaksson Я считаю, что кто-то должен понимать, что ОП просит .. –

ответ

4

Вы получаете исключение, потому что GlobalOnBoardingStepOneHandler наследует от BaseStepHandler<GlobalOnBoardingStepOneDataModel>, не BaseStepHandler<BaseStepDataModel>. Вероятно, это самая распространенная ошибка в распространении .NET. Дженерики не ковариантны для параметров типа.

См:

C#: cast to generic interface with base type

http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-two.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/10/17/covariance-and-contravariance-in-c-part-two-array-covariance.aspx

http://blogs.msdn.com/b/ericlippert/archive/2007/10/19/covariance-and-contravariance-in-c-part-three-member-group-conversion-variance.aspx

и т.д ...

Вопрос заключается в том, что вы предполагаете, что из-за GlobalOnBoardingStepOneDataModel унаследован от BaseStepDataModel, что GlobalOnBoardingStepOneHandler наследует от BaseStepHandler<BaseStepDataModel>. Это просто не так, и поэтому вы не можете отбрасывать от одного к другому.

В качестве примера рассмотрим следующее:

var myListOfStrings = new List<String>(); 

// By your logic, this should compile (it doesn't): 
var myListOfObjects = ((List<Object>)myListOfStrings); 

// But if it did, this would be possible: 
myListOfObjects.Add(1); // Holy cow, I just added an integer to a list of strings! What is the world coming to? 

Теперь, это очень запутанным для восстановления Java программистов, потому что это возможно в Java. В Java у вас есть стирание типа, так что во время выполнения List<String> на самом деле всего лишь List<Object>, и поэтому вы можете наложить его на все, что захотите, и поместить в него все, что захотите. Поскольку CLR использует реифицированные дженерики, а не тип стирания, List<String> фактически является отдельным и отличным от типа List<Object> или проблемы List<Integer>

+0

Я не понимаю, объясните, пожалуйста. – SexyMF

+0

Нет поддержки контравариантности/ковариации для общих параметров конкретных классов. Возможно, это ошибка, но я нахожу ее более отсутствующей функцией или невозможной функцией. –

+0

Как вы думаете, альтернативное решение? – SexyMF

3

здесь вы ждете контрвариантность ковариации для общих параметров конкретного типа.

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

Вы можете спроектировать интерфейс маркера, как это:

public interface IBaseStepHandler<out T> // "out" marks T as covariant 
    where T : BaseDataModel // Do you have a model base type? ;) 
{ 
    // Declare members here 
} 

Где я говорю «объявить членов здесь», просто объявить таких членов, которые являются частью вашего конкретного базового класса (я говорю о «BaseStepHandler»).

После этого реализовать этот интерфейс в базовом классе BaseStepHandler.

Теперь вы можете делать то, что вы хотите:

IBaseStepHandler<BaseDataModel> some = new WhateverBaseStepHandlerClass(); 

// This is possible because T generic parameter is covariant and it can be casted to `BaseDataModel`, or if you don't provide a `T` generic parameter constraint, you could cast it to `IBaseStepHandler<object>` too! 

Для того, чтобы узнать больше о ковариации, по этой ссылке: http://msdn.microsoft.com/en-us/library/ee207183.aspx

+1

Это предполагает, конечно, что он использует свой «BaseDataModel» ковариантным способом. Если это не так, это даже не будет компилироваться. –

+0

@ChrisShain Ну, но, возможно, решение его проблемы заставит его реорганизовать его код, поэтому он избегает этой проблемы ... Это зависит от него ... Я хотел показать ему способ достижения своей цели, к сожалению, никто не может себе представить масштаб и какие другие проблемы найдут его ... –

+0

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

Смежные вопросы