简体   繁体   English

声明实例的通用类型

[英]Declare generic type of instance

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. 有人知道吗,请告诉我。

Given that your MakePayment method does not require T , it would probably be simplest to declare that in a separate interface. 鉴于您的MakePayment方法不需要 T ,它很可能是最简单的声明,在一个单独的接口。 You could either make the generic interface extend the non-generic one: 您可以使通用接口扩展非通用接口:

// Capitalization fixed to comply with conventions
public interface IPayment
{
    void MakePayment(string orderNo);
}

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

Or just have them as separate interface: 或者只是将它们作为单独的界面:

public interface IPaymentHandler
{
    void MakePayment(string orderNo);
}

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

Either way, you then only need the non-generic interface in your Charge method. 无论哪种方式,您都只需要在Charge方法中使用非通用接口。

You could make Charge() and getPaymentInfo() be generic with respect to the type of PaymentModel : 你可以让Charge()getPaymentInfo()是通用对于类型PaymentModel

void Charge<TPaymentModel>(...) where TPaymentModel : PaymentModel {
    IPayment<TPaymentModel> payment = GetPayment<TPaymentModel>();
    // ...
    payment.MakePayment(getPaymentInfo<TPaymentModel>(...));
}

IPayment<TPaymentModel> GetPayment<TPaymentModel>() where TPaymentModel : IPaymentModel
{
    // Create payment of appropriate type based on typeof(TPaymentModel)
}

TPaymentModel GetPaymentInfo(...) where TPaymentModel : PaymentModel
{
    // Create payment model of appropriate type based on typeof(TPaymentModel)
}

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: 这仍然有点丑陋,要解决此问题,您可以引入一些新类,以从接口隐藏类型之间的对应关系,并使设计更合理:

/// Abstracts over different ways of making payments
interface IPaymentMaker 
{
    void MakePayment(string payType, long orderNo);
    // MakeRefund etc.
}

/// Refactor code common to all payment types here, and handle the association 
/// between payment and payment model.
class PaymentMakerBase<TPaymentModel> : IPaymentMaker 
    where TPaymentModel : IPaymentModel 
{
    void MakePayment(string payType, long orderNo) 
    {
        NewPayment().MakePayment(NewPaymentModel(payType, orderNo));
    }

    abstract IPayment<TPaymentModel> NewPayment();
    abstract TPaymentModel NewPaymentModel(string payType, long orderNo);
}

/// Handle only the differences between payment types that can't be put inside their
/// implementations
class PaypalPaymentMaker : PaymentMakerBase<PaypalPayment> 
{
    IPayment<PaypalPayment> NewPayment() { ... }
    PaypalPayment NewPaymentModel(...) { ... }
}

static class PaymentMakerFactory 
{
    /// The only "not type safe" part, handles parsing the payType string and 
    /// resolving it to the correct `PaymentMaker`
    public IPaymentMaker GetPaymentMaker(string payType) 
    {
        if (Regex.IsMatch(payType, ...)) 
        {
            // return appropriate payment maker for the payType
        }
        else if (...) 
        {
            // ...
        }
    }
}

Then, your controller code only looks like this: 然后,您的控制器代码仅如下所示:

PaymentMakerFactory.GetPaymentMaker(payType).MakePayment(payType, orderNo);

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 ( PaymentMakerFactory could probably be changed into a facade that creates the right payment maker and then calls MakePayment right away). 显然,可以通过删除多余项(在我包括的所有地方都不需要payType),使其更“客观”(而不是传递相同的参数列表)或更方便(可以将PaymentMakerFactory更改为外观创建正确的付款人,然后立即调用MakePayment )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM