Параметры типа - получить конкретный тип из типа T: IMyInterface - PullRequest
1 голос
/ 22 июля 2011

Предположим, у меня есть List<IMyInterface> ...

У меня есть три класса, которые реализуют IMyInterface: MyClass1, MyClass2 и MyClass3

У меня естьТолько для чтения Словарь:

private static readonly Dictionary<Type, Type> DeclarationTypes = new Dictionary<Type, Type>
{
    { typeof(MyClass1), typeof(FunnyClass1) },
    { typeof(MyClass2), typeof(FunnyClass2) },
    { typeof(MyClass3), typeof(FunnyClass3) },
};

У меня есть другой интерфейс, IFunnyInteface<T> where T : IMyInterface

У меня есть метод:

public static IFunnyInterface<T> ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
    if (DeclarationTypes.ContainsKey(node.GetType())) {
        IFunnyInterface<T> otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
        return otherClassInstance;
    }
    return null;
}

Я пытаюсь вызвать конструктор FunnyClassesи вставьте в качестве параметра мой объект MyClass.Я не хочу знать, какой это объект: я просто хочу создать экземпляр FunnyClass с MyClass в качестве параметра.

Что происходит, когда я вызываю ConvertToFunnyClass, T имеет тип IMyInterface, и когдаЯ пытаюсь привести его к FunnyInterface<T>, он говорит, что я не могу конвертировать FunnyClass1, например, в FunnyInterface<IMyInterface>

Мой текущий обходной путь (не красивый), это:

public static dynamic ConvertToFunnyClass<T>(this T node) where T : IMyInterface
{
    if (DeclarationTypes.ContainsKey(node.GetType())) {
        var otherClassInstance = (FunnyInterface<T>) Activator.CreateInstance(DeclarationTypes[node.GetType()], node);
        return otherClassInstance;
    }
    return null;
}

И мне это не нравится, потому что тип возвращаемого значения dynamic, поэтому, когда я получаю к нему доступ откуда-то еще, я понятия не имею, какой это тип, и я теряю intellisense и прочее.Я не знаю ни о каких последствиях для производительности.

Есть какие-нибудь подсказки?

Заранее спасибо!

Разрешение

КакЯ использую C # 4.0, я мог прекратить приводить ошибки, используя ковариацию (только выходные позиции), и поэтому я изменил свой IFunnyInterface на

IFunnyInteface<out T> where T : IMyInterface

Спасибо всем за ответы.

Ответы [ 2 ]

1 голос
/ 22 июля 2011

ответ thecoop точно указывает на то, почему вы не можете этого сделать.

Более чистым решением проблемы (помимо использования динамического) был бы базовый неуниверсальный интерфейс:

public interface IFunnyInterfaceBase
{
}

public interface IFunnyInteface<T> : IFunnyInterfaceBase 
    where T : IMyInterface
{
}

И вам нужно переместить сигнатуру методов, которую вы используете в этом коде, из IFunnyInteface в IFunnyInterfaceBase.

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

MyClass2 c2 = new MyClass2();
IFunnyInterfaceBase funnyInstance = c2.ConvertToFunnyClass();

Исключение, которое вы сказали, что вы получили в своем коде, не связано с самой сигнатурой метода расширения (метод в порядке) .. оно возникает в зависимости от типа вашего lvalue (типа переменной, которую вы используете для хранения его возврата значение)!

Очевидно, что это решение применимо, только если вы можете изменить исходный код IFunnyInterface!

1 голос
/ 22 июля 2011

По сути, ваша проблема в том, что вы пытаетесь конвертировать FunnyInterface<T> в FunnyInterface<IMyInterface>. Как уже упоминалось несколько раз (один пример - здесь , дополнительная информация здесь ), в большинстве случаев это недопустимо. Только в .NET 4, когда универсальный тип является интерфейсом или делегатом, а параметр типа был явно объявлен как вариант с in или out, вы можете выполнить это преобразование.

Является ли FunnyInterface на самом деле интерфейсом?

...