Создайте общий список, используя отражение - PullRequest
2 голосов
/ 03 сентября 2010

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

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

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

Спасибо!

Ответы [ 3 ]

2 голосов
/ 03 сентября 2010

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

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> не имеет конструкторов, поскольку он являетсяinterface.

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

0 голосов
/ 03 сентября 2010

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

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>();
}
0 голосов
/ 03 сентября 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...