开发者

C# Instantiate class which implements generic interface

开发者 https://www.devze.com 2022-12-30 12:45 出处:网络
I have some business classes which implements IBusinessRequest<T>, for example: public class PersonBusiness : IBusinessRequest<Person>

I have some business classes which implements IBusinessRequest<T>, for example:

public class PersonBusiness : IBusinessRequest<Person>
{ }

Besides this I have a function:

 TypeHelper.CreateBusinessInstance(Type businessType, Type businessRequestType)

A requirement of a business class is that they must have a parameterless constructor, which I check in the TypeHelper.CreateBusinessInstance function.

I want to create a instance of type businessType (which is PersonBusiness) with the generic value businessRequestType for IBusinessRequest<>.

How can I get this done?

EDIT1:

Thanks for all answers it putted me on the right track. The situation I wrote down was not the real situation I was dealing with. I hoped it was just enough to solve my problem :-)

I now came up with the following, which works like charm.

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;
        }

Now at runtime in a other part of the sofware the business class type is given to me (i.e PersonBusiness). Another fact is the part that I know the requestMessage which is the same that is given to IBusinessRequest. I need this requestMessage to set the property Request of the PersonBusiness class (which is implemented from IRequestMessage)

These two variables I give to static IBusiness CreateBusinessInstance(Type type, object requestMessage) which gives me back the IBusiness, which i further use to execute some business function.

Thanks all!

Gr

Martijn


Your question is somewhat unclear. Usually for generics where you want to create a new instance with a parameterless constructor, you use the new() constraint:

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

You can then use new T() within an implementation of IBusinessRequest<T>. No need to check it yourself - the compiler will do so.

However, it's not clear whether that's really what you're after here. What do you mean by "with the generic value businessRequestType for IBusiness<>"?


You can create a generic method with two generic type parameters - one for the business request type, and one for the implementing type:

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

And your example would use it like this:

IBusinessRequest<Person> request = CreateBusinessInstance<Person, PersonBusiness>();


Try this:

 Type[] typeArgs = { typeof(businessRequestType) };
return businessType.GetType.MakeGenericType(typeArgs);


Are you trying to create an instance of PersonBusiness when given the Person type?

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

var businessInstance = (IBusinessRequest<Person>)typeMap[typeof(Person)]();


See: How to dynamically create generic C# object using reflection?

EDIT 2: The parameter in businessRequestType is actually not needed. The Type businessType will, by definition, implement a single form of IBusinessRequest<> so there is no need pass businessRequestType. Modified solution accordingly.

EDIT 1: The problem is still a bit confusing. I think the problem is more constrained than you would like. All the combinations of businessType and businessRequestType need to be defined. You could use some variation of a tiered object factory such as this:

// 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;
}


Alternatively you could use another generic method:

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

You'd need to know the type at design time, but this might probably be fine (don't know your requirements exactly)...

Cheers Matthias


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;

This Manner you can inherite from a base class and invoke too the TModel Type

Hope this help

JU.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号