Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/273.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.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#_Factory_Class Visibility - Fatal编程技术网

C# 类实例创建限制

C# 类实例创建限制,c#,factory,class-visibility,C#,Factory,Class Visibility,我有许多实现相同接口的算法类;另一个“工厂”类负责通过配置参数实例化正确的算法类,然后在该实例上调用start方法 我想将算法类的构造函数(或任何其他实例创建机制)的可见性限制为仅限于工厂类 我怎样才能解决这个问题?我能想到的唯一干净的解决方案是将这些类移动到另一个.dll中,并将算法类更改为private,但这不是我现在想做的。也许您会对以下示例感到满意(是的,我知道通常不应该使用什么反射…) 在这里,您可以通过工厂创建算法实例。创建,而不是使用新算法。这不是您想要听到的答案,但:不要 通过使

我有许多实现相同接口的算法类;另一个“工厂”类负责通过配置参数实例化正确的算法类,然后在该实例上调用start方法

我想将算法类的构造函数(或任何其他实例创建机制)的可见性限制为仅限于工厂类


我怎样才能解决这个问题?我能想到的唯一干净的解决方案是将这些类移动到另一个.dll中,并将算法类更改为private,但这不是我现在想做的。

也许您会对以下示例感到满意(是的,我知道通常不应该使用什么反射…)


在这里,您可以通过工厂创建算法实例。创建,而不是使用新算法。

这不是您想要听到的答案,但:不要

通过使该构造函数成为私有/内部/受保护的,您就很难对算法进行测试,而且您还阻止了API的任何使用者手动选择自己的实现,而不是使用工厂

我想说的是让构造函数保持公共状态,只需确保在构造函数中声明了所需的每个依赖项。以下是我对构造函数的各种修饰符的看法:

  • public
    -每个人都可以访问你的构造函数,你可以测试这个类-这很好
  • protected
    -子类可以访问构造函数。这是可以的,但实际上只用于抽象类和/或构造函数链接
  • internal
    -您将构造函数的使用限制为
    InternalsVisibleTo
    (友元)程序集。这意味着程序集中的任何人都可以正常构造它,但其他程序集必须显式地是
    InternalsVisibleTo
    ,或者被迫使用您的工厂,从而将算法耦合到工厂
  • private
    -用于隐藏默认构造函数(尽管如果创建的构造函数至少包含一个参数,则无需执行此操作),或仅创建可链接的构造函数
TL;DR-我建议不要将构造函数
设置为内部
。通过这样做,您可能会使类
成为内部的
(您是通过它们的接口而不是它们的类引用算法,对吗?)


另一个解决方案是使类的实现成为私有的,并将它们嵌套在工厂中。让他们都实现一个公共接口(他们应该已经实现了),并将该接口公开给应用程序的其余部分。这仍然不能避免使其难以测试的问题。

如果我没弄错,这就是你想要的。如果工厂和算法在同一个DLL中,只需使它们的构造函数
内部
(当然,该DLL中的所有内容都可以在不使用工厂的情况下创建它们的实例)。在C语言中,没有C++之类的代码<朋友>代码>的概念,所以不能让私有的东西对选定的类/函数可见。如果您想确保不会忘记调用工厂方法(即使在同一个DLL中),那么您可以使构造函数
私有
,并为每个类声明一个工厂
内部
方法(它本身是无用的,但它会帮助您防止错误,因为它更显式)。您可以使算法的构造函数必须将工厂作为参数,虽然这不会隐藏可见性,但您可以使它在有人试图使用它时导致错误。如果您希望您的构造函数是公共的,那么您可以签入正在进行调用的构造函数,如果它继续来自工厂类;否则抛出异常;。但是,由于使用反射,这将降低性能。我们对他的需求了解不多,他可能需要为每个类实现一个接口,但这是可行的。也就是说,拥有一个内部构造函数也是一样的。这对考试有害吗?不,用户将看到通过工厂方法创建的对象,这就是您必须测试的。如果构造函数是内部的,是否需要将类设置为内部的?不,它们是不同的东西…通过依赖工厂,你不再测试算法,而是测试工厂和算法。这对于集成测试来说很好,但通常算法需要某种形式的单元测试。这就是为什么我建议让算法有公共构造函数并单独测试它们。是的,类和内部构造函数是不同的。但是,如果无法创建对象(通过构造函数),则无需通过对象的实现(类)访问对象。这就是为什么我说他最好将类设置为internal而不是构造函数,如果它是类上唯一的构造函数的话。保持类为公共的唯一原因是执行类似于
var myAlgorithm=(MyAlgorithmImplementation)factory.GetAlgorithm()的操作
where
factory.GetAlgorithm()
返回
IAlgorithm
IMO即使您没有公共构造函数,也可能希望拥有公共类。例如,当对象创建是类内部的(不仅因为工厂方法),而且它的使用是外部的。即使通过工厂方法GetAlgorithm()也不需要是无类型的:如果您有GetAlgorithm(),那么t可以是完全返回的类型(不是基类或最派生的类型),但对象以某种方式初始化,您希望客户端不知道这些细节。用例列表是无穷无尽的…我只是看不到这里的用例。也就是说,我肯定会有一个接口支持这一点,我肯定会想对算法进行单元测试,这就是我提出建议的原因。我确信您正在创建您的用例,因为您以前使用过给定的用例,所以我不会说您的用例是错误的:-)
public class Algorithm
{
    private Algorithm()
    {
    }

    public void SomeMethod()
    {
    }
}

public static class Factory
{
    public static Algorithm Create()
    {
        var constructor = typeof(Algorithm).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null);
        return (Algorithm)constructor.Invoke(null);
    }
}