How to declare variable that is for generic type of instance?
In controller, I need to create instance that depend on payment type, and each class has different type of parameter. That’s why I used generic type.
But I don’t know what type I need to set to define variable for each payment class.
Models for parameter
public class PaymentModel
{
public string orderNo { get; set;}
}
public class CCPaymentModel : PaymentModel
{
public string CCNo {get; set;}
public string expDate {get; set;}
}
public class PaypalPaymentModel : PaymentModel
{
public string paypalID {get; set;}
}
public class GooglePaymentModel : PaymentModel
{
public string googleID {get; set;}
}
Interface class, I use Generic type parameter because each payment type need different type of parameter.
public interface IPayment<T> where T : PaymentModel
{
void makePayment(string orderNo);
void makeRefund(T refundInfo);
}
Models,
public class SagePayment
: IPayment<CreditCardPaymentInfo>
{
public void MakePayment( CreditCardPaymentInfo creditCardPaymentInfo ) {
// make payment
}
public void MakeRefund( CreditCardPaymentInfo creditCardPaymentInfo ) {
// make refund
}
}
public class GooglePayment
: IPayment<GooglePaymentModel>
{
public void MakePayment( GooglePaymentModel paymentInfo ) {
// make payment
}
public void MakeRefund( GooglePaymentModel paymentInfo ) {
// make refund
}
}
public class PaypalPayment
: IPayment<PayPalPaymentModel>
{
public void MakePayment( PayPalPaymentModel paymentInfo ) {
// make payment
}
public void MakeRefund( PayPalPaymentModel paymentInfo ) {
// make refund
}
}
Controller (Create instance)
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();
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();
payinfo = getPaymentInfo(paytype, orderNo); // it return GooglePaymentModel type object
}
paymentProcess.MakePayment(payinfo);
}
To avoid error, I could this,
public void Charge(string paytype,orderNo){
if (Regex.IsMatch(paytype, "^Credit Card"))
{
IPayment<CCPaymentModel> paymentProcess = new SagePayment();
payinfo = getPaymentInfo(paytype, orderNo);
paymentProcess.MakePayment(payinfo);
}
else if (Regex.IsMatch(paytype, "^PayPal"))
{
IPayment<PaypalPaymentModel> paymentProcess = new PayPalPayment();
payinfo = getPaymentInfo(paytype, orderNo);
paymentProcess.MakePayment(payinfo);
}
else if (Regex.IsMatch(paytype, "^Google"))
{
IPayment<GooglePaymentModel> paymentProcess = new GooglePayment();
payinfo = getPaymentInfo(paytype, orderNo);
paymentProcess.MakePayment(payinfo);
}
}
public void Refund(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();
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();
payinfo = getPaymentInfo(paytype, orderNo); // it return GooglePaymentModel type object
}
paymentProcess.MakeRefund(payinfo);
}
But I know it is not right way.
Anybody know, please advice me.
You could make
Charge()andgetPaymentInfo()be generic with respect to the type ofPaymentModel:This is still a little ugly, to resolve this you could introduce a few new classes to hide the correspondence between the types from the interfaces and make the design more sound:
Then, your controller code only looks like this:
Obviously the above design could be improved by removing redundancies (payType probably isn’t needed everywhere I include it), making it more “objecty” (instead of passing identical argument lists around), or more convenient (
PaymentMakerFactorycould probably be changed into a facade that creates the right payment maker and then callsMakePaymentright away).