Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/300.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/8/design-patterns/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
C# 使用泛型实现类型安全的枚举模式_C#_Design Patterns_Generics_Enums_Type Safety - Fatal编程技术网

C# 使用泛型实现类型安全的枚举模式

C# 使用泛型实现类型安全的枚举模式,c#,design-patterns,generics,enums,type-safety,C#,Design Patterns,Generics,Enums,Type Safety,如何在泛型类上实现类型安全枚举模式?让我们假设它是按照这些思路实现的 public class KnownSetting<T> { public readonly static KnownSetting<String> Name = new KnownSetting<String>("name", "Default Name", t => t); public readonly static KnownSetting<int>

如何在泛型类上实现类型安全枚举模式?让我们假设它是按照这些思路实现的

public class KnownSetting<T>
{
    public readonly static KnownSetting<String> Name = new KnownSetting<String>("name", "Default Name", t => t);
    public readonly static KnownSetting<int> Size = new KnownSetting<String>("size", "25", t => Converter.ToInt32);

    public String Key { get; set; }
    public T DefaultValue { get; set; }
    public Func<String, T> Converter { get; set; }

    private KnownSetting(String key, T defaultValue, Func<String, T> converter)
    {
        Key = key;
        DefaultValue = defaultValue;
        Converter = converter;
    }
}
公共类知识设置
{
public readonly静态KnownSetting Name=新KnownSetting(“Name”,“Default Name”,t=>t);
公共只读静态KnownSetting Size=新KnownSetting(“Size”,“25”,t=>Converter.ToInt32);
公共字符串密钥{get;set;}
公共T默认值{get;set;}
公共函数转换器{get;set;}
私有知识设置(字符串键、T默认值、Func转换器)
{
钥匙=钥匙;
DefaultValue=DefaultValue;
转换器=转换器;
}
}
模式的实现是正确的,因为构造函数仍然是私有的,但使用此构造函数时,它看起来是错误的:

public static class Program
{
    public static void main()
    {
        var x = KnownSetting<?>.Name;
    }
}
公共静态类程序
{
公共静态void main()
{
var x=KnownSetting.Name;
}
}
然后,一个选项是将其拆分为两部分,即KnownSetting容器类和设置实现,但构造函数的作用域不能是私有的,以便从容器中实例化

如何实现此模式,使其泛型方面对最终用户隐藏,但保持强类型?是否有更合适的模式,或者有更好的方法来实现它

更新
我添加了第二个示例来说明我确实希望设置的类型是泛型的。

在新类中声明静态数据:

public class KnownSetting
{
    public readonly static KnownSetting<String> Name = new KnownSetting<String>("name", "Default Name", t => t);
    public readonly static KnownSetting<int> Size = new KnownSetting<String>("size", "25", t => Converter.ToInt32);
}
公共类知识设置
{
public readonly静态KnownSetting Name=新KnownSetting(“Name”,“Default Name”,t=>t);
公共只读静态KnownSetting Size=新KnownSetting(“Size”,“25”,t=>Converter.ToInt32);
}

它在C#中可以有相同的名称,因为类名在名称加泛型类型参数计数上是唯一的。

在基类型中创建一个使用其他类型的帮助器方法,并创建一个已知的设置类。您需要Create方法,因为基本构造函数正在设置(string、object、Func)。这也是我引入另一个通用变量(U)的原因:

公共类知识设置:设置
{
私有知识设置(字符串键、对象defaultValue、Func转换器):基(键、defaultValue、转换器){}
公共只读静态设置Name=Create(“Name”,“Default Name”,t=>t);
公共只读静态设置Size=Create(“Size”,25,t=>Convert.ToInt32(t));
}
公共班级设置
{
公共字符串密钥{get;set;}
公共T默认值{get;set;}
公共函数转换器{get;set;}
受保护的静态设置创建(字符串键、U默认值、Func转换器)
{
返回新设置(键、默认值、转换器);
}
保护设置(字符串键、T默认值、Func转换器)
{
钥匙=钥匙;
DefaultValue=DefaultValue;
转换器=转换器;
}
}
公共静态类程序
{
静态void Main(字符串[]参数)
{
var x=KnownSetting.Name;
}
}

也许我遗漏了什么,但为什么不直接使用您的
知识设置类,并从新类中对相同的枚举实例进行新引用呢?比如:

public static class KnownSettings {
  public readonly static KnownSetting<string> Name = KnownSetting<string>.Name;
  public readonly static KnownSetting<int> Size = KnownSetting<int>.Size;
  // etc.
}

对于每个
T
,静态字段都有一个单独的值。你不会想要的。我能想到的最好方法是将构造函数内部化,并遵循你的“容器类”思想,那么你只需要在同一个程序集中依赖程序员的规程。@SLaks为什么我不想要它?@default.kramer当然,你是对的,依赖规程是可行的,但如果我能通过在设计上多花一点时间来防止任何错误,那是值得的。@spools除非
KnownSetting.Name!=KnownSetting.Name
可以。此外,您可以从
KnownSetting
继承
KnownSetting
,因此有一个“通用”非类型表单,您可以根据需要将它们组合在一起。但是
KnownSetting
的构造函数需要公开才能起作用。@usr关闭。虽然不完美,但这是迄今为止最好的主意。正如您在我的解决方案中看到的那样,它也可以得到保护,从而正确地隐藏它。请注意,您不能直接使用受保护的ctor;你是对的,它必须是内部的,老实说,这总是让我口齿不清…@StefandeBruijn在我的代码中,我在调用内部函数时非常小心。我总是问自己:我应该叫这个吗?对于公共函数,我总是假设我可以调用它们而不违反体系结构。这个惯例解决了我的问题。这有什么帮助?预定义有一个专用的ctor,但未使用。这里的设置缺少通用和私有的ctor,这是问题的核心。你是对的,我误解了这个问题。我改变了解决方案以反映问题;这应该是他想要的答案。如果你有受保护的Create,为什么不让ctor私有呢?这与类型有关。ctor的类型具有设置([…]),因此您无法调用设置的ctor(因为它不是您的基类)。在我的代码中,这可以通过调用Setting.Create来避免,它位于基类中,因此可以调用Setting(位于同一范围内)。您需要继承才能工作,因此您需要某种类型的受保护的ctor。希望有点道理。。。试试看-它不会编译:-),因为KnownSetting和KnownSetting(没有泛型)不是同一个类,所以非泛型不能看到私有的或泛型的构造函数。@Spooles:但它不需要看到构造函数,它只需要看到构造的
public readonly static
字段。所有
KnownSetting
值都可以完全在
KnownSetting
内部构造,但是客户端仍然可以通过另一个类上的另一个字段访问这些值。
public static class KnownSettings {
  public readonly static KnownSetting<string> Name = KnownSetting<string>.Name;
  public readonly static KnownSetting<int> Size = KnownSetting<int>.Size;
  // etc.
}
var x = KnownSettings.Name;