2008-11-20 6 views
2

У меня есть общая функция, которая получает интерфейс как тип, теперь в одном условии мне нужно создать новый класс в зависимости от интерфейса. Я думал об этом, и способ решить это будет использовать IoC, но я надеялся, что будет другой путь, потому что IoC кажется немного переполненным.C# - создать экземпляр класса в зависимости от предоставленного интерфейса в общем классе

ниже является попыткой использования шаблона посетителя:

public class RepositoryManager<T> : IRepositoryManager<T> where T : class, new() 
{ 
    public T GetOrCreate(string id) 
    { 
     T item = (T)CreateNew(new T(), id); 
     return item; 
    } 
} 

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

Другая идея, которую я имел, заключалась в том, могу ли я сделать объявление где-то вроде или?

public class RepositoryManager<T> : IRepositoryManager<T> where T : class, Iabc or Ixyz, new() 

Я надеюсь, что вопрос ясен :)

-Марк


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

Проблема заключается в том, что метод может иметь много различных интерфейсов, возложенных на него, например:

RepositoryManager класса:

private static IMedicament CreateNew(IMedicament emptyType, string id) 
{ 
    return new Medicament { Id = id }; 
} 
private static IRefund CreateNew(IRefund emptyType, string id) 
{ 
    return new Refund { Id = id }; 
} 

RepositoryManager<Iabc> abcRepository = new RepositoryManager<Iabc>(); 
RepositoryManager<Ixyz> xyzRepository = new RepositoryManager<Ixyz>(); 

Iabc abc = abcRepository.GetOrCreate("12345"); 
Ixyz xyz = xyzRepository.GetOrCreate("12345"); 

поэтому использование T item = (T)CreateNew(new T(), id); не будет работать, потому что я должен сказать ему, что T может быть либо типа Iabc, либо Ixyz, но при этом я получаю следующую ошибку:

Вызов неоднозначен между следующими способами или свойствами: RepositoryManager<T>.CreateNew(IMedicament, string) и RepositoryManager<T>.CreateNew(IRefund, string)

Было бы неплохо, если бы я получил эту работу, просто скопировав код несколько раз.

+1

Я не понимаю, в чем ваш вопрос. Что ты пытаешься сделать? Напишите метод, который принимает интерфейс как тип (параметр?) И создает класс, который реализует интерфейс? (Это потребует реестр или поиск в поиске.) Или что-то еще? – 2008-11-20 00:29:07

ответ

1

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

Я не достаточно знаком с кодом, чтобы знать, как RhinoMocks выполняет это, но поскольку он является open source, вы можете получить некоторые идеи, но посмотрите на его исходный код.

http://ayende.com/projects/rhino-mocks/downloads.aspx

0

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

public void Method<T>() 
{ 
    Type type = typeof(T); 

    T newObject = (T)type.GetConstructor(new System.Type[] { }).Invoke(new object[] { }); 
} 

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

2

И почему это не работает?

public class RepositoryManager<T> : IRepositoryManager<T> where T : Ixyz, new() 
{ 
    public T GetOrCreate(string id) 
    { 
     T item = (T)CreateNew(new T(), id); 
     return item; 
    } 
} 

Альтернатива, если вы не можете использовать новый() должен передать в качестве делегата, чтобы создать объект (или совместимый тип):

public class RepositoryManager<T> : IRepositoryManager<T> where T : Ixyz 
{ 
    private Func<T> _tConstructor; 

    public RepositoryManager(Func<T> tConstructor) 
    { 
     this._tConstructor = tConstructor; 
    } 

    public T GetOrCreate(string id,) 
    { 
     T item = (T)CreateNew(this._tConstructor(), id); 
     return item; 
    } 
} 
2

Я не уверен, я понимаю, вопрос полностью, но я использовал что-то подобное раньше.

public class Repository 
{ 
    public T Create<T>(string id) where T : class 
    { 
     return Activator.CreateInstance(typeof(T), new[] { id }) as T; 
    } 
} 
1

Как добиться того, чтобы IRefund и IMedicament реализовали общий интерфейс, который имеет свойства Id?

0

Возможно, для вас может быть выполнено следующее: 1) создать словарь, где типом является ваш интерфейсом (T параметра) и объект является фиктивной экземпляр объекта, который может быть создан, 2) пусть ваш фиктивный объект будет заводом новых объектов, которые реализуют Т.

Вашему RepositoryManager просто нужно инициализировать словарь с помощью поддерживаемых пар-интерфейс-объект, где несколько интерфейсов могут сопоставляться с одним и тем же объектом (при необходимости).