Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 只让抽象类知道其继承者_C#_Asp.net - Fatal编程技术网

C# 只让抽象类知道其继承者

C# 只让抽象类知道其继承者,c#,asp.net,C#,Asp.net,我正在为我的网站制作一个支付系统。用户可以从多个支付提供商中选择一个进行支付,但所有支付提供商的行为都应相同。我想这样来表现这种行为: public abstract class PaymentProvider { private static var methods = Dictionary<String,PaymentProvider> { {"paypal",new PaymentProviderPaypal()}, {"worl

我正在为我的网站制作一个支付系统。用户可以从多个支付提供商中选择一个进行支付,但所有支付提供商的行为都应相同。我想这样来表现这种行为:

public abstract class PaymentProvider {
    private static var methods = Dictionary<String,PaymentProvider>
    {
        {"paypal",new PaymentProviderPaypal()},
        {"worldpay",new PaymentProviderWorldpay()}
    }

    public static Dictionary<String,PaymentProvider> AllPaymentProviders
    {
        get {return methods;}
    }

    public abstract pay();
}

public class PaymentProviderPaypal : PaymentProvider {
    public override pay() {

    }
}

public class PaymentProviderWorldpay : PaymentProvider {
    public override pay() {

    }
}
您应该通过编写PaymentProvider.AllPaymentProviders[key].pay来使用它。其思想是,使用此类的函数不需要知道底层支付提供者是如何实现的,它们只需要知道密钥

但是,目前,如果您可以访问PaymentProvider类,那么您也可以访问继承类。可以实例化继承类的新副本,并以意外的方式使用它们。我想封装继承类,以便只有抽象PaymentProvider知道它们

我该怎么做?不同的保护级别(如protected)在这里不起作用-在Java中,protected意味着只有命名空间中的其他类可以使用该类,但在C中,它意味着其他一些东西


我的想法对吗?或者我应该使用不同的方法吗?

我想到了几个选项:

将其与客户机代码放在一个单独的程序集中,并将实现抽象化 将实现作为私有嵌套类放在PaymentProvider类中。您仍然可以通过使PaymentProvider成为分部类来分离源代码-每个实现使用一个源文件 如果您不介意在程序集方面将客户机与实现分离,那么第一个选项可能是最干净的

请注意,在Jamiec的答案提出更改后,这两个选项仍然有效-可见性部分与继承部分有些正交


顺便说一句,我希望这种方法真的被称为付费而不是付费:

你的继承权有点不可靠,我很想用一种类似但截然不同的方式来做

public interface IPaymentProvider
{
  void Pay()
}

// Implementations of IPaymentProvider for PaypalPaymentProvider & WorldpayPaymentProvider

public static class PaymentHelper
{
    private static var providers = Dictionary<String,IPaymentProvider>
    {
        {"paypal",new PaymentProviderPaypal()},
        {"worldpay",new PaymentProviderWorldpay()}
    }


    public static void Pay(string provider)
    {
        if(!providers.Containskey(provider))
            throw new InvalidOperationException("Invalid provider: " + provider);

        providers[provider].Pay();
    }

}

这不是问题的答案:在.NET internal中,允许访问当前程序集中的所有名称空间,受保护的名称空间仅可供继承者访问。依靠用户知道使用哪个键传递给AllPaymentProviders,而不是公开类型,还有什么好处?@Jamiec我在MSDN上看到了这一点。但是,该网站是visual studio下的“网站”项目,这与程序集有关,因此我不想在发生意外情况时使用“内部”。也没有答案:即使在Java中,受保护的内容更多地与继承有关,而不是包。@StevenJeuris继承者可以在其构造函数中有不同的设置,例如为提供者打开测试事务,以及更改ID/密码/设置。我希望最终在一个配置文件中的一个地方初始化所有这些文件,而不是让人们能够访问它们,以按照自己的意愿实例化它们。我可以记录下哪些密钥是有效的,这样用户就知道该调用哪个密钥了。谢谢您的回答。我想我同意你的第二个建议。目前网站的结构不适合将支付代码放在不同的程序集中,我计划最终解决这个问题。为什么使用接口比使用抽象类更好?它是否使它更易于维护/更快?实际上没有区别-使用抽象类的唯一原因是如果您有一些基本实现-我使用接口进行演示。
public interface IPaymentProvider
{
  void Pay(double amount);
}

public static void Pay(string provider, double amount)
{
    if(!providers.Containskey(provider))
        throw new InvalidOperationException("Invalid provider: " + provider);

    providers[provider].Pay(amount);
}