создать экземпляр класса, реализующий универсальный интерфейс, используя отражение - PullRequest
3 голосов
/ 21 июня 2011

У меня есть следующее в сборке бизнес-логики:

public class BusinessEntity
{
    ...
}

public class Customer : BusinessEntity
{
    ...
}

public interface IEntityManager <T> where T : BusinessEntity
{
    T SaveData(T oData);
}

public CustomerEntityManager : IEntityManager <Customer>
{
    Customer SaveData(Customer o)
    {
        ...
    }
}

Я вынужден загрузить вышеуказанную сборку (по нескольким очевидным причинам) в моем текущем проекте посредством отражения и создания экземпляра CustomersEntityManager. Представьте, что я пишу метод следующим образом:

public class EntityFactory
{
  public static IEntityManager<BusinessEntity> GetManagerInstance(string EntityName)
  {
     var asm = GetAssembly(); // imagine that I loaded the assembly somehow
     EntityName = "Customer"; // just imagine
     object o;     
     // DO NOT KNOW WHAT TO WRITE HERE.
     return o as IEntityManager<BusinessEntity>; // this needs to be an instance of CustomerEntityManager.
  }
}

У меня есть возможность изменить бизнес-сборку. Но создание экземпляра должно быть в моем текущем проекте, и я должен загрузить бизнес-сборку, используя отражение. Все типы данных будут известны только во время выполнения.

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

UPDATE:

последовал совет "driss", вроде следующего:

string fullTypeName = "Your.Namespace." + EntityName + "EntityManager";
object o = Activator.CreateInstance(asm.FullName, fullTypeName);

Похоже, он создал экземпляр. Однако это привело к ошибке:

Невозможно привести 'o' (который имеет фактический тип 'CustomerEntityManager') к 'IEntityManager'

когда выполняется следующая инструкция:

return o as IEntityManager<BusinessEntity>

Спасибо

Ответы [ 3 ]

3 голосов
/ 21 июня 2011

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

string fullTypeName = "Your.Namespace." + EntityName + "EntityManager";
object o = Activator.CreateInstance(asm.FullName, fullTypeName);

Тогда это просто вопрос вызова Activator.CreateInstance, как вы видите.

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

Re: Ваш комментарий:

Вы не можете привести CustomerEntityManager к IEntityManager, потому что это не то, что он реализует - он реализует только IEntityManager. Если бы приведение было разрешено, безопасность типов была бы нарушена (вы могли бы передать BusinessEntity, когда реализация явно ожидает Заказчика, или, по крайней мере, так сказано в контракте. (Отклонение Co / contra не может вас здесь сохранить, потому что T входит и в IEntityManager, и в него).

1 голос
/ 21 июня 2011

Забудьте об использовании низкоуровневого отражения самостоятельно, много не очень удобной работы. Если возможно, используйте инфраструктуру IoC, т. Е. StructureMap . С StructureMap вам просто нужно создать реестр, который знает все зависимости (например, CustomersEntityManager - это наша реализация для IEntityManager<Customer>). Более менее похоже на это:

For<IEntityManager<Customer>>().Use<CustomersEntityManager>()

А теперь, если вы попросите свой контейнер StructureMap для реализации IEntityManager<Customer>, вы получите CustomersEntityManager:

ObjectFactory.GetInstance<IEntityManager<Customer>>(); // will return instance of CustomersEntityManager

Если вы не знаете запрошенный тип во время компиляции, вы можете запросить менеджера сущностей, используя простой Type экземпляр:

string entityName = "Customer";
Type entityType = Type.GetType(entityType);
Type requestedType = typeof(IEntityManager<>).MakeGenericType(new[] { entityType });
ObjectFactory.GetInstance(requestedType); // will also return CustomersEntityManager instance

Реестр может быть определен в вашей сборке, не затрагивая бизнес-сборку.

0 голосов
/ 21 июня 2011

Оформить заказ Activator.CreateInstance()

Object o = Activator.CreateInstance (asm.FullName, EntityName );

даст вам экземпляр Customer. Я не уверен, как бы вы перешли от Customer до CustomerEntity, но я уверен, что вы можете решить эту часть.

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