views:

210

answers:

4

Possible Duplicate:
Create instance of generic type?

How can I pass a param to a generic contstructor?

 public class Payment<T>  where T: HostFunctionContext, IClaimPayment, new()  
{

    public IResultEntity Display(MyUser user, string claim, int? cert)
    {
        **HostFunctionContext func = new T(user) as HostFunctionContext;**  <~doesn't compile        
        IClaimPayment payment = new T();
        payment.ClaimNumber = claimNumber;
        payment.CertificateSequence = certSequence;

        return payment.DisplayEntity();

    }

}

 public sealed partial class CardPayment : HostFunctionContext
{
    public CardPayment(MyUser user) : base(user) { }

}

constructor for abstract HostFunctionContext

public HostFunctionContext(MyUser user) {

        _hostConnection = HostConnectionAssembler.GetHostConnection();
        _functionParams = FunctionParamsAssembler.GetFunctionParams();
        if (user != null) {
            _hostConnection.Login = user.Login;

        }
    }

I need to pass the user to the baseclass of T. How can I do this? Do I create a parameterless constructor, then a property of type MyUser, then on the set of that property push that to the baseclass? The abstract baseclass has no myUser property and no parameterless constructor. I am really stuck here.

Thanks for any help, ~ck

+3  A: 

The new() keyword by definition restricts your generic parameter to be a reference type with a public, parameterless constructor. When you instantiate a "new T()", it has to use reflection to create an instance of it.

You may want to use a factory pattern to create your objects instead of trying to do it through a generic constructor. You could pass the type into the factory and have the factory logic pass you back the correct object type, initialized with the user.

womp
Why would a compiler have to use reflection?
David B
Who said anything about the compiler? See here for a good explanation: http://stackoverflow.com/questions/367577/why-does-the-c-compiler-emit-activator-createinstance-when-calling-new-in-with-a
womp
@David B: Because there's nothing built into IL to express "construct a new instance of this type parameter using a parameterless constructor".
Jon Skeet
I guess "it" in my post is ambiguous. I see how you interpreted that. I'll try an edit.
womp
A: 

I've not tried this myself but surely (for the right type) you could just use properties on the interface to get what you need?

T foo = new T{ Prop1="BAR", Prop2="BAZ" }
annakata
T would have to expose those properties through an interface which is supplied as part of the constraints, but that might work.
Steve Gilham
Oh yeah, "use properties on the interface" - I assume that the OPs IClaimPayment has these or can be extended to have them.
annakata
A: 

If you don't have a base parameterless constructor, you're not going to be able to use generics like that. One option is to require the Payment constructor to receive "instructions" for how to build its T, via a delegate:

public class Payment<T> where T: HostFunctionContext, IClaimPayment
{
    private Func<MyUser, T> ContextBuilder { get; set; }
    public Payment(Func<MyUser, T> contextBuilder)
    {
        ContextBuilder = contextBuilder;
    }

    public IResultEntity Display(MyUser user, string claim, int? cert)
    {
        T context = ContextBuilder(user);

        IClaimPayment payment = context as IClaimPayment;
        payment.ClaimNumber = claimNumber;
        payment.CertificateSequence = certSequence;

        return payment.DisplayEntity();
    }
}

// Usage:
var MyCreditPayment = new Payment<CreditPayment>(user => new CreditPayment(user));

There are other patterns to achieve this, but ultimately you're going to need some way to encapsulate how your context gets created.

dahlbyk
A: 

You might want to look into Activator.CreateInstance. You can pass arguments into the constructor this way.

SwDevMan81