tags:

views:

324

answers:

6

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

+3  A: 

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
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
@Martijn: But isn't that determined by `businessType`? For example, with `PersonBusiness`, you've got to use `Person` haven't you?
Jon Skeet
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<T> interface?
Martijn B
@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
+1  A: 

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
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<T> where T is the given parameter businessRequestType
Martijn B
@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
No your right didn't see this at first.
Martijn B
A: 

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

Mudu
Both types are not known at designtime and are dynamicly choosen in runtime.
Martijn B
+3  A: 

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
I don't know my types until runtime
Martijn B
+1  A: 

See: http://stackoverflow.com/questions/1151464/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;
}
Jerry Fernholz
Checking this out looks promising, it's not realy the same do
Martijn B
You might be wrong in "The Type businessType will, **by definition**, implement a single form of IBusinessRequest<>". It can implement any number of IBusinessRequest<T> interfaces. It depends on the problem domain.
Martinho Fernandes
@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
@Jerry: Sorry for the confusion. Yes, there is no need to know about the interface type parameter whatsoever.
Martinho Fernandes
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
+2  A: 

Try this:

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