2009-02-04 7 views
2

Мое приложение обрабатывает IList. Илисты разных пользовательских типов. Я думаю, что я могу использовать отражение, чтобы посмотреть, какой тип объекта содержит IList, а затем создать новый экземпляр этого типа и впоследствии добавить его самому IList?Динамическое создание нового экземпляра типа IList

Так что в любой момент я мог бы обрабатывать

IList<Customer> l; 

, и я хотел бы создать новый экземпляр Клиента

Customer c = new Customer(0, "None") 

, а затем добавить, что на список

l.Add(c); 

Очевидно, что делать это динамически во время выполнения является основной проблемой. Надеюсь, кто-нибудь может дать мне несколько указателей. Спасибо brendan

+0

Подсказка Вы должны указать свой Ланг я думаю, его в C#, но она должна быть там, где некоторые .... – Peter

+0

да, я просто понял, что при просмотре постановка вопроса сам, благодаря – user48408

ответ

4

Попробуйте это:

public static void AddNewElement<T>(IList<T> l, int i, string s) 
    { 
     T obj = (T)Activator.CreateInstance(typeof(T), new object[] { i, s }); 
     l.Add(obj); 
    } 

Использование:

IList<Customer> l = new List<Customer>(); 
    l.Add(new Customer(1,"Hi there ...")); 

    AddNewElement(l, 0, "None"); 

(EDIT):

Попробуйте тогда:

public static void AddNewElement2(IList l, int i, string s) 
    { 
     if (l == null || l.Count == 0) 
      throw new ArgumentNullException(); 
     object obj = Activator.CreateInstance(l[0].GetType(), new object[] { i, s }); 
     l.Add(obj); 
    } 
+0

Я думаю, что это сработает, но способ, которым я обрабатываю списки, не позволяет этого. т.е. Еогеаспа (IList л в arrayOfPopulatingLists) { AddNewElement (л, 0, "None") } // Компилятор ошибка: Аргументы методы не могут быть выведены из эксплуатации. Нужно ли мне искать общие методы? – user48408

+0

См. Мой обновленный ответ ... –

+0

Спасибо Бруно, отлично работает – user48408

0

Большая проблема здесь: если вы не знаете тип, как вы знаете, как создать новый? Не каждый тип в мире имеет конструктор, который принимает int и строку.

0

Да, извините, я должен был упомянуть, что набор объектов, которые будут обрабатываться, будет иметь конструктор, который принимает int и строку.

2

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

void Process<T>(IList<T> list, int x, string y) where T : MyBase, new() 
    { 
     T t = new T(); 
     t.X = x; 
     t.Y = y; 
     list.Add(t); 
    } 

Где MyBase является базой для классов, которые обнажают ИНТ и строковые свойства , Если хотите, вы можете использовать интерфейс, а не базовый класс.

+0

Этот код не работает , и нет ничего подобного для достижения этого эффекта. –

+0

К сожалению, вы правы, соответственно отредактировали сообщение. Спасибо –

+0

Это выглядит хорошо. С точки зрения использования. У меня есть массивList из IList, который я обрабатываю в foreach. Итак, foreach (IList l в arrayOfILists) {Process (l, 0, «None»); } не собирается компилировать, что является новым для дженериков, я не понимаю, почему not (?) – user48408

1

Вы можете использовать метод Activator.CreateInstance для вызова конструктора для класса с помощью его имени типа (в виде строки) или экземпляра System.Type.

+0

Проблема в том, что тип (-ы) есть/находятся в другой сборке, поэтому я не верю, что могу вызвать Activator.CreateInstance – user48408

+1

Пока сборка правильно загружена, это не должно быть проблемой. –

+0

спасибо. Activator.CreateInstance works – user48408

1

Я думаю, вы должны измените свой дизайн. Вы можете использовать abstract factory pattern. Использование отражения ухудшит производительность.

Вот код для завода.

public abstract class MyStore { 
    public abstract string Name { get; } 
    public abstract void AddItem(int id, string name); 
} 

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

Затем создайте магазин для клиентов.

public class CustomerStore : MyStore, IEnumerable<Customer> { 
    List<Customer> list = new List<Customer>(); 

    public override string Name { get { return "Customer Store"; } } 
    public override void AddItem(int id, string name) { 
     list.Add(new Customer(id, name)); 
    } 
    public IEnumerator<Customer> GetEnumerator() { 
     return list.GetEnumerator(); 
    } 
} 

Использование

foreach (MyStore store in List<MyStore>) 
    store.AddItem(0, "None"); 

Если вы хотите, чтобы рассмотреть тип хранилища, используйте

switch (store.Name) { 
case "Customer Store": 
    SomeMethod((CustomerStore)store); 
    break; 
default: 
    throw new WhatEverException(); 
} 
1

Вы можете использовать метод Type.GetGenericArguments возвращать аргумент типа родового типа IList < T>. Затем вызовите соответствующий конструктор.

Type T = l.GetType ().GetGenericArguments () [ 0 ]; 
    ConstructorInfo ctor = T.GetConstructor (
    new Type [ 2 ] { typeof (int), typeof (string) }); 
    System.Diagnostics.Debug.Assert (ctor != null); 
    object instance = ctor.Invoke (
    new object [ 2 ] { 0, "None" }); 
0

Лучший способ получить тип IList является взгляд на тип недвижимости индексатора!

var collectionType = targetList.GetType().GetProperty("Item").PropertyType; 
var constructor = collectionType.GetConstructor(Type.EmptyTypes); 
var newInstance = constructor.Invoke(null); 
Смежные вопросы