2013-09-05 1 views
1

Пример кода:C#, создавая типичный тип - с аргументом переменной типа?

void Foo(params object[] objects) 
{ 
    var entries = new List<IEntry>(); 
    foreach(var o in objects) 
    { 
     var entry = new Entry<o.GetType()>(); // this doesn't work 
     entries.Add(entry); 
    } 

    ... 
} 

Foo("hello", 5); // should fill entries with Entry<string> and Entry<int> 

Почему это не возможно? Думаю, мне нужно вместо этого работать с отражением? Как это сделать правильно и результативно?

+0

Это лучшая практика: 'Activator.CreateInstance (typeof (Entry <>). MakeGe nericType (o.GetType())); '? –

+4

Так как вы все равно рассматриваете объект как универсальный IEntry, зачем вообще использовать дженерики? – dtb

+0

Это только на данный момент, позже пользователь может определить общий аргумент с свойством IEntry.Type. Не кажется вам приятным, я полагаю, однако, я не могу дать весь контекст. –

ответ

3

Вы просто не можете использовать C# дженерики так, как вы пытаетесь сделать в вашем фрагменте кода.

Для использования [C#] дженериков фактический тип объекта должен быть известен во время компиляции.

Вы пытаетесь динамически передать тип объекта в качестве параметра типа. Это просто невозможно.

Редактировать

Да, можно динамически создавать общие объекты с помощью отражения. В конце концов, generics реализуется как как построение Cycle-time C#, так и как функция .NET framework (в отличие от, скажем, Java, где это только функция времени компиляции, основанная на тире Erasure). Таким образом, в .NET посредством рефлексии можно реализовать последнее «обход» первого (что, опять же, было бы невозможно в Java).

Но ОП явно не нуждается в этом.

В конце концов, entries является List<IEntry>. IOW, контейнер entriesне «знает» конкретный тип его элементов (поскольку он связан с интерфейсом). Таким образом, если каждый элемент будет добавлять уже реализует IEntry, то это будет достаточно:

void Foo(params IEntry[] objects) 
{ 
    var entries = new List<IEntry>(); 
    foreach(var o in objects) 
    { 
     entries.Add(o); 
    } 

    ... 
} 

Ото, если эти объекты не реализуют IEntry, то OP просто нужен список чистый, обычный, старой школы, из нетипизированных объекты:

void Foo(params object[] objects) 
{ 
    var entries = new List<object>(); 
    foreach(var o in objects) 
    { 
     entries.Add(o); 
    } 

    ... 
} 

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

+1

-1 Отражение ... – siride

+0

@siride: каким образом отражение противоречит тому, что я сказал о ** generics ** ....? – rsenna

+1

@tEsTA, проблема заключается в том, что использование отражения для ввода аргумента типа в 'Entry <>' * использует generics *. Что касается CLR, то это то же самое, что и компилятор. Полезность этого трудно судить без лишнего контекста. –

3

Вы можете сделать это с отражением

var entryType = typeof(Entry<>); 
Type[] typeArgs = { o.GetType() }; 
var genericType = entryType.MakeGenericType(typeArgs); 
IEntry entry = (IEntry)Activator.CreateInstance(genericType); 
+0

Во-первых, я не буду понижать вас (я уже дал альтернативный ответ). Во-вторых, код правильный. Но я не думаю, что это действительно помогает OP: он, кажется, пытается использовать дженерики для случая использования, которые не являются необходимыми дженериками **, и вы пытаетесь заставить его использовать рефлексию только для того, чтобы сделать дженерики work (и imho вы терпите неудачу, поскольку создание «общих объектов» путем отражения далеко не совпадает с тем, что правильно использует C# generics). – rsenna

+2

@tEsTA, об этом ответе ничего не говорится о том, что «не удается» вопрос, заданный OP. Бывают случаи, когда использование рефлексии для таких дженериков как раз и есть то, что нужно, и без дополнительного контекста от ОП нет возможности судить о том, недостаточно ли этого решения. –

+0

@KirkWoll: Я не думаю, что вы действительно поняли, что я сказал. Опять же: создание общих аргументов с отражением ** не является тем же самым, что и с использованием генераторов C#. Да, иногда, где-то это как-то полезно. Кажется, это не так. – rsenna

1

Вам нужна функция вида:

Func<Type, IEntry> 

Я предложил бы добавить статическую функцию родительского Foo, как это:

public static IEntry Make(Type type) 

Внутри этой функции, не стесняйтесь добавлять любые код имеет смысл для вас:

if (type == typeof(string)) 
{ 
    return new StringEntry(); //Obviously some special logic based on the type. 
} 
else 
{ 
    //Default logic 
    return (IEntry) Activator.CreateInstance(typeof(Entry<>).MakeGenericType(type)); 
} 
Смежные вопросы