C # Создайте класс, который реализует универсальный интерфейс - PullRequest
0 голосов
/ 18 мая 2010

У меня есть несколько бизнес-классов, которые реализуют IBusinessRequest<T>, например:

public class PersonBusiness : IBusinessRequest<Person>
{ }

Помимо этого у меня есть функция:

 TypeHelper.CreateBusinessInstance(Type businessType, Type businessRequestType)

Требование бизнес-класса состоит в том, что у них должен быть конструктор без параметров, который я проверяю в функции TypeHelper.CreateBusinessInstance.

Я хочу создать экземпляр типа businessType (который является PersonBusiness) с общим значением businessRequestType для IBusinessRequest<>.

Как мне это сделать?

EDIT1:

Спасибо за все ответы, это поставило меня на правильный путь. Ситуация, которую я записал, не была реальной ситуацией, с которой я имел дело. Я надеялся, что этого было достаточно, чтобы решить мою проблему: -)

Теперь я придумал следующее, которое работает как шарм.

public interface IBusinessRequest<T> where T : class
{
    T Request { get; set; }
}

public interface IBusiness
{        
    /// <summary>
    /// Validates the request against custom rules
    /// </summary>        
    /// <param name="meldingen">Return a list of validation messages</param>
    /// <returns>returns true is validation went succesfull, false when something is wrong</returns>
    bool Validate(out List<string> meldingen);

    /// <summary>
    /// Executes business logic and returns a response object.
    /// </summary>        
    /// <returns>The strongly typed response object</returns>
    object Execute(object request);
}


public class PersonBusiness :IBusiness, IBusinessRequest<Person>
{ }


public static IBusiness CreateBusinessInstance(Type type, object requestMessage)
        {            
            //some checks on the type, like: is of IBusiness & IBusinessRequest<>
            ...

            //get al constructors of type
            ConstructorInfo[] constructors = type.GetConstructors();

            //if we have more then one constructor throw error
            if (constructors.Length > 1)
            {
                throw new BusinessCreateException(String.Format(PrivateErrors.ToManyConstructorsInTypeError, type, constructors.Length, 1));
            }

            //constructor parameters
            ParameterInfo[] parameterInfo = constructors[0].GetParameters();

            //we do not allow a constructor with more then one parameters.
            if (parameterInfo.Length > 0)
            {
                throw new BusinessCreateException(String.Format(PrivateErrors.ConstructorHasToManyParametersError, type, 0));
            }

            IBusiness instance = null;            
            try
            {                
                //create an instance, invoke constructor with zero parameters
                object invokeResult = constructors[0].Invoke(new object[0]);

                //set property "Request"
                PropertyInfo pi = type.GetProperty("Request");

                //do we have found a property
                if (pi != null)
                {
                    pi.SetValue(invokeResult, requestMessage ,null);
                }

                instance = invokeResult as IBusiness;
            }
            catch (Exception ex)
            {
                throw new BusinessCreateException(String.Format(PrivateErrors.BusinessCreateError, type.FullName), ex);
            }

            //return result
            return instance;
        }

Теперь во время выполнения в другой части программного обеспечения мне присваивается тип бизнес-класса (т.е. PersonBusiness). Другим фактом является то, что я знаю, что requestMessage является тем же, что и IBusinessRequest. Мне нужно это requestMessage для установки свойства Request класса PersonBusiness (который реализован из IRequestMessage)

Эти две переменные я передаю статическому IBusiness CreateBusinessInstance (тип Type, object requestMessage), который возвращает мне IBusiness, который я далее использую для выполнения некоторой бизнес-функции.

Спасибо всем!

Gr

Мартейн

Ответы [ 7 ]

4 голосов
/ 18 мая 2010

Ваш вопрос несколько неясен. Обычно для генериков, где вы хотите создать новый экземпляр с конструктором без параметров, вы используете ограничение new():

public interface IBusinessRequest<T> where T : new()

Затем вы можете использовать new T() в реализации IBusinessRequest<T>. Не нужно проверять это самостоятельно - компилятор сделает это.

Однако, не ясно, действительно ли это то, что вы здесь. Что вы подразумеваете под "с общим значением businessRequestType для IBusiness<>"?

3 голосов
/ 18 мая 2010

Вы можете создать универсальный метод с двумя параметрами универсального типа - один для типа бизнес-запроса и один для типа реализации:

public static IBusinessRequest<T> CreateBusinessInstance<T, TImpl>() where TImpl : IBusinessRequest<T>, new()
{
    return new TImpl();
}

И ваш пример будет использовать это так:

IBusinessRequest<Person> request = CreateBusinessInstance<Person, PersonBusiness>();
2 голосов
/ 18 мая 2010

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

 Type[] typeArgs = { typeof(businessRequestType) };
return businessType.GetType.MakeGenericType(typeArgs);
1 голос
/ 18 мая 2010

См .: Как динамически создать универсальный объект C # с помощью отражения?

EDIT 2: параметр в businessRequestType фактически не нужен. Тип businessType по определению будет реализовывать одну форму IBusinessRequest <>, поэтому нет необходимости передавать businessRequestType. Измененное решение соответственно.

РЕДАКТИРОВАТЬ 1: Проблема все еще немного запутанная. Я думаю, что проблема более ограничена, чем вы хотели бы. Все комбинации businessType и businessRequestType должны быть определены. Вы можете использовать несколько вариантов фабрики многоуровневых объектов, например:

// Creates an instance of T that implements IBusinessRequest<R>
public static IBusinessRequest<R> CreateBusinessInstance<T, R>() where T :
    IBusinessRequest<R>
{
    return Activator.CreateInstance<T>();
}


// Creates an instance of businessType that implements 
// IBusinessRequest<businessRequestType>
public static object CreateBusinessInstance(Type businessType)
{
    object biz = null;

    if (typeof(PersonBusiness) == businessType)
    {
        biz = CreateBusinessInstance<PersonBusiness, Person>();
    }
    //else if ... other business types


    if (null == biz)
    {
        throw new ApplicationException("Unknown type");
    }

    return biz;
}
1 голос
/ 18 мая 2010

Вы пытаетесь создать экземпляр PersonBusiness, когда указан тип Person?

var typeMap = new Dictionary<Type, Func<object>>
{
    { typeof(Person), () => new PersonBusiness() }
};

var businessInstance = (IBusinessRequest<Person>)typeMap[typeof(Person)]();
0 голосов
/ 27 апреля 2011
public class GridController<TModel> : Web.Controllers.ControllerBase where TModel : new()
    {
        public ActionResult List()
        {
            // Get the model (setup) of the grid defined in the /Models folder.
            JQGridBase gridModel = new TModel() as JQGridBase;

Этот манер, который вы можете унаследовать от базового класса и также вызывать TModel Type

Надеюсь, эта помощь

JU.

0 голосов
/ 18 мая 2010

В качестве альтернативы вы можете использовать другой универсальный метод:

IBusinessRequest<T> CreateBusinessInstance<T>(T businessType) where T : new() {
}

Вам нужно знать тип во время разработки, но, возможно, это будет хорошо (не знаю ваших требований точно) ...

Приветствие Matthias

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