0

[EDIT]

I organize my question again,

Models for parameter

public class PaymentModel
{   
    ... 
}

public class CCPaymentModel : PaymentModel
{
    ...
}

public class PaypalPaymentModel : PaymentModel
{
    ...
}

public class GooglePaymentModel : PaymentModel
{
    ...
}    

Interface class

public interface IPayment<T> where T : PaymentModel
{
    ...
}

Models (get inheritance from IPayment),

public class SagePayment
    : IPayment<CreditCardPaymentInfo>
{
    public void MakePayment( CreditCardPaymentInfo creditCardPaymentInfo ) {
        // ...
    }

    public void MakeRefund( CreditCardPaymentInfo creditCardPaymentInfo ) {
        // ...
    }
}

public class GooglePayment
    : IPayment<GooglePaymentModel>
{
    public void MakePayment( GooglePaymentModel paymentInfo ) {
        // ...
    }

    public void MakeRefund( GooglePaymentModel paymentInfo ) {
        // ...
    }
}

public class PaypalPayment
    : IPayment<PayPalPaymentModel>
{...}

Controller (Create instance)

IPayment<???> paymentProcess; // //Error    1   Using the generic type 'com.WebUI.Models.IPayment<T>' requires 1 type arguments

if (Regex.IsMatch(paytype, "^Credit Card"))
{
    paymentProcess = new SagePayment(); // it need CCPaymentModel type parameter
}
else if (Regex.IsMatch(paytype, "^PayPal"))
{
    paymentProcess = new PayPalPayment(); // it need PaypalPaymentModel type parameter
}
else if (Regex.IsMatch(paytype, "^Google"))
{
    paymentProcess = new GooglePayment(); // it need GooglePaymentModel type parameter
}

[EDIT]

public void Charge(string paytype,orderNo){

    IPayment<???> paymentProcess; // //Error    1   Using the generic type 'com.WebUI.Models.IPayment<T>' requires 1 type arguments
    Object payinfo;

    if (Regex.IsMatch(paytype, "^Credit Card"))
    {
        paymentProcess = new SagePayment(); // <== Error, Can not casting
        payinfo = getPaymentInfo(paytype, orderNo); // it return CCPaymentModel type object
    }
    else if (Regex.IsMatch(paytype, "^PayPal"))
    {
        paymentProcess = new PayPalPayment();
        payinfo = getPaymentInfo(paytype, orderNo); // it return PaypalPaymentModel type object
    }
    else if (Regex.IsMatch(paytype, "^Google"))
    {
        paymentProcess = new GooglePayment(); // it return GooglePaymentModel type object
        payinfo = getPaymentInfo(paytype, orderNo); 
    }

    paymentProcess.MakePayment(payinfo);
}

enter image description here

[EDIT #2]

With this,

public interface IPayment {
}

public interface IPayment<T> : IPayment where T : PaymentModel
{
    void MakePayment(string pickno);
    void makeRefund(T refundInfo);
}

I got an error, Error 1 'com.WebUI.Models.IPayment' does not contain a definition for 'MakePayment' and no extension method 'MakePayment' accepting a first argument of type 'Ecom.WebUI.Models.IPayment' could be found (are you missing a using directive or an assembly reference?)

So, to avoid that error, I move MakePayment method to upper interface class,

public interface IPayment {
    void MakePayment(string pickno);
}

public interface IPayment<T> : IPayment where T : PaymentModel
{
    void makeRefund(T refundInfo);
}

Now, the error is gone, BUT how should I do in makeRefund case? I can not move to upper interface class because I need generic type parameter.

Could you help me a little more please?

10
  • 2
    You would want to have another IPayment interface without the generics from which IPayment<T> inherits from. That is: public interface IPayment<T> : IPayment where T : PaymentModel. Commented Nov 5, 2012 at 16:00
  • 1
    You are going to need this method to create the generic type via reflection: msdn.microsoft.com/en-us/library/…. Commented Nov 5, 2012 at 16:02
  • 1
    You need to instantiate something that implements IPayment<GooglePayment>. There is no such class in your sample. You cannot instantiate an interface. Commented Nov 5, 2012 at 16:09
  • 1
    @fsimonazzi I think @Expert has GooglePayment, PayPalPayment, etc classes (but not shown here) which implement from IPayment<GooglePaymentModel> or IPayment<PayPalPayment> respectively. Commented Nov 5, 2012 at 16:19
  • 1
    @ChrisSinclair got it - would have helped to see those classes. Commented Nov 5, 2012 at 16:21

1 Answer 1

6

You would want to have another IPayment interface without the generics from which IPayment inherits from. That is:

public interface IPayment
{

}

public interface IPayment<T> : IPayment where T : PaymentModel
{

}

EDIT: If you really don't want to have an IPayment base interface, then you'd have to treat them as type object:

object paymentProcess;

if (Regex.IsMatch(paytype, "^Credit Card"))
{
    paymentProcess = new SagePayment();
}
else if (Regex.IsMatch(paytype, "^PayPal"))
{
    paymentProcess = new PayPalPayment();
}
else if (Regex.IsMatch(paytype, "^Google"))
{
    paymentProcess = new GooglePayment();
}

But that might cost you later; regardless you're going to have to cast to work with the specific implementation types. You're really best using a base interface. You may even use it in a nice way:

public interface IPayment
{
    PaymentModel Payment { get; }
}

So you can reference and use the PaymentModel without knowing that it's actually a GooglePaymentModel specifically.

EDIT: Based on your comment, you might have something like:

public interface IPayment
{
    void MakePayment(string pickno);
}

public interface IPayment<T> : IPayment where T : PaymentModel
{
    void MakeRefund(T refundInfo);
}

You could even have a non-generic MakeRefund version typed against PaymentModel so your calling code might not care if it's a GooglePayment or not. (but that could cause other issues if they pass a PayPalPayment, so that's up to you)

EDIT: Based on your latest code, you'll want something like this:

public interface IPayment
{

}

public interface IPayment<T> : IPayment where T : PaymentModel
{
    void MakePayment(T paymentInfo);
    void MakeRefund(T paymentInfo);
}

Your controller/factory would look like:

//not sure on the exact signature since you didn't provide it
public IPayment CreatePayment(string paytype)
{
    IPayment paymentProcess = null;

    if (Regex.IsMatch(paytype, "^Credit Card"))
    {
        paymentProcess = new SagePayment();
    }
    else if (Regex.IsMatch(paytype, "^PayPal"))
    {
        paymentProcess = new PayPalPayment();
    }
    else if (Regex.IsMatch(paytype, "^Google"))
    {
        paymentProcess = new GooglePayment();
    }

    return paymentProcess
}

Your usage code would somewhere have to cast it to the known payment type to use:

IPayment untypedPayment = Factory.CreatePayment("PayPal");
IPayment<PayPalPaymentModel> typedPayment = (IPayment<PayPalPaymentModel>)untypedPayment;
typedPayment.MakePayment(new PayPalPaymentModel());

//or alternatively
IPayment untypedPayment = Factory.CreatePayment("PayPal");  
PayPalPayment typedPayment = (PayPalPayment)untypedPayment;
typedPayment.MakeRefund(new PayPalPaymentModel());

EDIT: Based on your latest edits, this is what you want. Drive your base IPayment calls against a PaymentModel. Then in the specific implementations you can cast or type-check at runtime:

public interface IPayment
{
    void MakePayment(PaymentModel paymentInfo);
    void MakeRefund(PaymentModel paymentInfo);
}

public interface IPayment<T> : IPayment where T : PaymentModel
{

}

public class GooglePayment
    : IPayment<GooglePaymentModel>
{
    public void MakePayment(PaymentModel paymentInfo) {
    GooglePaymentModel googlePayment = (GooglePaymentModel)paymentInfo;
    // ...
    }

    public void MakeRefund(PaymentModel paymentInfo) {
    GooglePaymentModel googlePayment = (GooglePaymentModel)paymentInfo;
    // ...
    }
}

Then your Controller:

public void Charge(string paytype,orderNo){

    IPayment paymentProcess = null;
    PaymentModel payinfo = null;

    if (Regex.IsMatch(paytype, "^Credit Card"))
    {
        paymentProcess = new SagePayment();
        payinfo = getPaymentInfo(paytype, orderNo);
    }
    else if (Regex.IsMatch(paytype, "^PayPal"))
    {
        paymentProcess = new PayPalPayment();
        payinfo = getPaymentInfo(paytype, orderNo);
    }
    else if (Regex.IsMatch(paytype, "^Google"))
    {
        paymentProcess = new GooglePayment();
        payinfo = getPaymentInfo(paytype, orderNo); 
    }

    paymentProcess.MakePayment(payinfo);
}

public PaymentModel getPaymentInfo(string paytype,orderNo)
{
    //return some payment model
}
Sign up to request clarification or add additional context in comments.

8 Comments

I have 2 methods in IPayment now, which class do I need to put the methods in? (void MakePayment(string pickno), void makeRefund(T refundInfo))
@Expertwannabe Depends if they're strongly typed to the PaymentModel or not. MakePayment probably can be promoted to the base class, but makeRefund wouldn't be.
Thank you for your help, but I couldn't solve the problem still. Could you review my edited question again please? I rewrite with more codes.
I edited my question again with new controller code, could you review again please? I'm so sorry for bordering you.
@Expertwannabe I've added another edit. Also from your code/error/screenshot, you need to have IPayment<T> inherit from IPayment. See the very first code block in my original answer. Your IPayment<T> is not currently inheriting from IPayment. You need to fix that.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.