如何声明适用于泛型类型实例的变量?
在控制器中,我需要创建依赖于支付类型的实例,并且每个类都有不同类型的参数。这就是我使用泛型的原因。 但我不知道我需要为每个支付类别定义变量的类型。
参数模型
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;}
}
接口类,我使用Generic类型参数,因为每种支付类型都需要不同类型的参数。
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);
}
但我知道这不是正确的方法。
有人知道,请指教。
答案 0 :(得分:3)
鉴于您的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
方法中的非通用接口。
答案 1 :(得分:1)
您可以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可能在我包含它的任何地方都不需要),使它更“对象”(而不是传递相同的参数列表),或更方便({{1}可能会被改成 facade ,它会创建正确的付款机制,然后立即调用PaymentMakerFactory
。