[英]Declare generic type of instance
如何声明适用于实例通用类型的变量?
在控制器中,我需要创建依赖于支付类型的实例,并且每个类都有不同类型的参数。 这就是为什么我使用泛型类型。 但是我不知道我需要设置哪种类型来定义每个付款类别的变量。
参数模型
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;}
}
接口类,我使用通用类型参数,因为每种付款类型都需要不同类型的参数。
public interface IPayment<T> where T : PaymentModel
{
void makePayment(string orderNo);
void makeRefund(T refundInfo);
}
楷模,
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
}
}
控制器(创建实例)
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);
}
为避免错误,我可以这样做,
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);
}
但是我知道这不是正确的方法。
有人知道吗,请告诉我。
鉴于您的MakePayment
方法不需要 T
,它很可能是最简单的声明,在一个单独的接口。 您可以使通用接口扩展非通用接口:
// 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);
}
或者只是将它们作为单独的界面:
public interface IPaymentHandler
{
void MakePayment(string orderNo);
}
public interface IRefundHandler<T> where T : PaymentModel
{
void MakeRefund(T refundInfo);
}
无论哪种方式,您都只需要在Charge
方法中使用非通用接口。
你可以让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)
}
这仍然有点丑陋,要解决此问题,您可以引入一些新类,以从接口隐藏类型之间的对应关系,并使设计更合理:
/// 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 (...)
{
// ...
}
}
}
然后,您的控制器代码仅如下所示:
PaymentMakerFactory.GetPaymentMaker(payType).MakePayment(payType, orderNo);
显然,可以通过删除多余项(在我包括的所有地方都不需要payType),使其更“客观”(而不是传递相同的参数列表)或更方便(可以将PaymentMakerFactory
更改为外观创建正确的付款人,然后立即调用MakePayment
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.