2010-09-03 3 views
2

У меня есть функция, которая использует отражение для установки свойств объекта A из объекта B. В какой-то момент мне нужно создать экземпляр общей коллекции. Однако я не могу заставить его работать. Вот что у меня есть сейчас:Создать общий список, используя отражение

IList list = destProperty.PropertyType.GetGenericTypeDefinition() 
       .MakeGenericType(destProperty.PropertyType.GetGenericArguments()) 
       .GetConstructor(Type.EmptyTypes) 
       .Invoke(null) as IList; 

Я пытаюсь установить значение destProperty. Он должен быть списком Во время выполнения destProperty имеет тип ICollection <>. Я думаю, что происходит, так как ICollection - это интерфейс, у него нет конструктора. Каков правильный способ его создания?

Спасибо!

ответ

2

Я переписан код, в виде примера (мы надеемся, что соответствует тому, что вы пытаетесь сделать! =), Чтобы попытаться сделать его более ясным, в чем проблема:

public class Program 
{ 
    public struct MyType 
    { 
     public ICollection<string> MyProperty { get; set; } 
    } 
    static void Main(string[] args) 
    { 
     var type = typeof(MyType); 
     var properties = type.GetProperties(); 
     var destProperty = properties[0]; 

     var genericTypeDefinition = destProperty.PropertyType.GetGenericTypeDefinition(); 
     var madeGenericType = genericTypeDefinition.MakeGenericType(destProperty.PropertyType.GetGenericArguments()); 
     var ctor = madeGenericType.GetConstructor(Type.EmptyTypes); 
    } 
} 

Если поставить точку останова на предпоследней скобкой вы увидите, что ctor возвращается как null, что, потому что, как вы правильно догадались, ICollection<T> не имеет конструкторов из-за его интерфейс.

Из-за этого нет «супер-общего» способа сделать это, потому что нет никакого неотъемлемого способа сказать: «Какая лучшая реализация ICollection<T> для использования в этой ситуации». Вам нужно будет принять это решение и new один, основываясь на информации, полученной от отражения.

0

Вы не можете создать экземпляр интерфейса. Что вы делаете может do представляет собой типичный тип, который реализует этот интерфейс. В вашем случае вам нужно получить тип, представляющий общий список <>, а затем вызвать MakeGenericType.

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

0

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

Type interfaceType = destProperty.PropertyType; 
return typeof(MyClass) 
    .GetMethod("CreateList", BindingFlags.NonPublic | BindingFlags.Static) 
    .MakeGenericMethod(interfaceType.GetGenericArguments()) 
    .Invoke(null, new object[] { }); 

private static IList CreateList<T>() 
{ 
    return new List<T>(); 
}