0

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

Martijn B
  • 4,065
  • 2
  • 29
  • 41

7 Answers7

4

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<>"?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Sorry for not being clear. I mean that the T value has to be of type businessRequestType which is given as parameter. TypeHelper.CreateBusinessInstance(Type businessType, Type businessRequestType) – Martijn B May 18 '10 at 15:48
  • 2
    @Martijn: But isn't that determined by `businessType`? For example, with `PersonBusiness`, you've got to use `Person` haven't you? – Jon Skeet May 18 '10 at 16:12
  • You are totaly right. This is determined by the "businessType". Didn't see that at first. So now I can create an instance of type "businessType" which is returned as an object. Is it posible to dynamicly cast this to the IBusinessRequest interface? – Martijn B May 19 '10 at 07:37
  • 1
    @Martijn: You'd need to know T - or be in a generic method. The cast would be pointless unless you could actually use the interface afterwards. – Jon Skeet May 19 '10 at 08:19
3

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>();
Lee
  • 142,018
  • 20
  • 234
  • 287
2

Try this:

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

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)]();
dtb
  • 213,145
  • 36
  • 401
  • 431
  • I am trying to instantiate a business class for example PersonBusiness which is the type "businessType" I get as a parameter from TypeHelper.CreateBusinessInstance. The problem is that this type implements a generic inferface IBusinessReques where T is the given parameter businessRequestType – Martijn B May 18 '10 at 15:53
  • 2
    @Martijn B: You don't need to know the generic parameters of an implemented interface to create an instance of a class, or am I wrong? – dtb May 18 '10 at 16:05
1

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;
}
Community
  • 1
  • 1
Jerry Fernholz
  • 685
  • 5
  • 11
  • Checking this out looks promising, it's not realy the same do – Martijn B May 18 '10 at 16:08
  • 1
    You might be wrong in "The Type businessType will, **by definition**, implement a single form of IBusinessRequest<>". It can implement any number of IBusinessRequest interfaces. It depends on the problem domain. – R. Martinho Fernandes May 18 '10 at 17:03
  • 1
    @Martinho Fernandes - sort of, the point was that whatever interfaces a particular BusinessType implements is fixed by the class definition and so there is no reason to pass it to the CreateBusinessInstance method. It's not obvious, at least to me, what you would do with the businessRequestType parameter. – Jerry Fernholz May 18 '10 at 19:34
  • 1
    Sorry for the confusion. Yes, there is no need to know about the interface type parameter whatsoever. – R. Martinho Fernandes May 18 '10 at 20:29
  • You are both totally right. I don't need the "businessRequestType" for instantiating the "businessType". Didn't see that at first. The reason I was given it as a parameter is to cast the created instance to the implemented generic interface. That is where problem is, can I cast it to implemented generic interface? – Martijn B May 19 '10 at 07:43
0

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

Matthias Meid
  • 12,455
  • 7
  • 45
  • 79
0
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.

Julien
  • 121
  • 13