Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/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#_C# 4.0_Static Methods - Fatal编程技术网

C# 除了奇怪的重复模板模式,还有其他选择吗?

C# 除了奇怪的重复模板模式,还有其他选择吗?,c#,c#-4.0,static-methods,C#,C# 4.0,Static Methods,在过去的几周里,我对这种模式感到有些头疼 以下是我的两个问题: 如何改进以下示例: public class DocketType : Enumeration<DocketType, int, string> { public static DocketType Withdrawal = new DocketType(2, "Withdrawal"); public static DocketType Installation = new DocketType

在过去的几周里,我对这种模式感到有些头疼

以下是我的两个问题:

如何改进以下示例:

public class DocketType : Enumeration<DocketType, int, string>
{
    public static DocketType Withdrawal = new DocketType(2, "Withdrawal");
    public static DocketType Installation = new DocketType(3, "Installation");

    private DocketType(int docketTypeId, string description) 
        : base(docketTypeId, description) { }
}
正如您将从我的第二个链接问题中看到的,这个问题的问题是调用
Enumeration.Resolve(X值)不会导致实例化
DocketType
静态对象

我并不反对完全从头重写。我知道这是一种很大的代码气味。目前,为了使其正常工作,我的基类具有受保护的静态方法
ChildResolve
,并且我已将
Resolve
添加到我的每个枚举类中。讨厌的东西

回答:

似乎没有很好的替代模式,因此我坚持使用该模式,并从公认的答案中汲取灵感,得出以下结论:

static Enumeration()
{
    GetAll();
}

public static void GetAll()
{
    var type = typeof(TEnum);
    var fields = type.GetFields(BindingFlags.Public | 
        BindingFlags.Static | BindingFlags.DeclaredOnly);

    foreach (var info in fields)
    {
        var locatedValue = info.GetValue(null) as Enumeration<TEnum, X, Y>;
        Cache.Add(locatedValue.Value, locatedValue);
    }
}
静态枚举()
{
GetAll();
}
公共静态void GetAll()
{
var类型=类型(TEnum);
var fields=type.GetFields(BindingFlags.Public |
BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach(字段中的var信息)
{
var locatedValue=info.GetValue(null)作为枚举;
Cache.Add(locatedValue.Value,locatedValue);
}
}
这也是codecampservermvc示例项目中使用的相同代码,因此使用它我感觉不那么脏

您希望“对给定类型的所有子类”执行某些操作。如果不使用AppDomain.Current.GetAssemblies()并对其进行迭代,任何此类性质的操作都是不可能的。如果采用这种方法,可以通过创建仅应用于程序集(以及应包含在子类搜索中的其他程序集)的程序集级属性来优化性能,并在准备对每个程序集调用.GetTypes()时使用该属性

为了清楚起见,下面是一个获取所有这些子类的示例:

Type[] subclasses = AppDomain.CurrentDomain.GetAssemblies()
    .Where(x => Attribute.IsDefined(typeof(MyEnumeartionAssemblyAttribute)))
    .SelectMany(x => x.GetTypes())
    .Where(x => x.BaseType != null && 
           x.BaseType.IsGenericType && 
           x.BaseType.GetGenericTypeDefinition() == typeof(Enumeration<,,>));
Type[]subclass=AppDomain.CurrentDomain.getAssemblys()
.Where(x=>Attribute.IsDefined(typeof(MyEnumeartionAssemblyAttribute)))
.SelectMany(x=>x.GetTypes())
.Where(x=>x.BaseType!=null&&
x、 BaseType.IsGenericType&&
x、 BaseType.GetGenericTypeDefinition()==typeof(枚举));

从这里开始,在每个系统上使用反射应该是一个简单的问题。键入静态字段并执行您想要的操作。

您需要将静态字段推送到一个类中,该类具有一个静态实例作为实例字段。这样,您就可以通过一个静态成员访问枚举,该静态成员立即引用所有枚举成员

一个快速组合的示例:

// The Collection of values to be enumerated
public class DocketEnum : EnumarationCollection<DocketType, int, string>
{
        // Values are fields on a statically instanced version of this class
    public DocketType Withdrawal = new DocketType(2, "Withdrawal");
    public DocketType Installation = new DocketType(3, "Installation");

    // The publicly accessible static enumeration 
    public static DocketEnum Values = new DocketEnum();
}

// The actual value class
public class DocketType : EnumerationValue<DocketType, int, string>
{
        // Call through to the helper base constructor
    public DocketType(int docketTypeId, string description) 
        : base(docketTypeId, description) { }
}

// Base class for the enumeration
public abstract class EnumarationCollection<TType, X, Y>
    where TType : EnumerationValue<TType, X, Y> 
{
            // Resolve looks at the static Dictionary in the base helpers class
    public TType Resolve(X value)
    {
        return Cache[value] as TType;
    }

    public static Dictionary<X, EnumerationValue<TType, X, Y> > Cache = new Dictionary<X, EnumerationValue<TType, X, Y>>();
}

// Base class for the value
public abstract class EnumerationValue<TType, X, Y> 
    where TType : EnumerationValue<TType, X, Y> 
{        
        // helper constructer talks directly the the base helper class for the Enumeration
    protected EnumerationValue(X value, Y displayName)
    {
        EnumarationCollection<TType, X,Y >.Cache.Add(value, this as TType);
    }
}



class MainClass
{
    public static void Main (string[] args)
    {
                    // You can immediately resolve to the enumeration
        Console.WriteLine(DocketEnum.Values.Resolve(2).ToString());
    }
}
//要枚举的值的集合
公共类DocketEnum:EnumarationCollection
{
//值是此类的静态实例化版本上的字段
公共案卷类型撤回=新案卷类型(2,“撤回”);
公共DocketType安装=新DocketType(3,“安装”);
//可公开访问的静态枚举
公共静态DocketNum值=新DocketNum();
}
//实际值类
公共类DocketType:枚举值
{
//调用helper基构造函数
公共DocketType(int docketTypeId,字符串描述)
:base(docketTypeId,description){}
}
//枚举的基类
公共抽象类EnumarationCollection
其中TType:EnumerationValue
{
//Resolve查看基本helpers类中的静态字典
公共TType解析(X值)
{
将Cache[value]返回为TType;
}
公共静态字典缓存=新字典();
}
//值的基类
公共抽象类枚举值
其中TType:EnumerationValue
{        
//helper构造函数直接与枚举的基helper类对话
受保护的枚举值(X值,Y显示名称)
{
EnumarationCollection.Cache.Add(值,此为TType);
}
}
类主类
{
公共静态void Main(字符串[]args)
{
//您可以立即解析为枚举
Console.WriteLine(docketnum.Values.Resolve(2.ToString());
}
}

它不是很优雅,但像这样的东西可能会奏效:

public class DocketType : Enumeration<DocketType, int, string>
{
    public static readonly DocketType Withdrawal =
        new DocketType(2, "Withdrawal");

    public static readonly DocketType Installation =
        new DocketType(3, "Installation");

    private DocketType(int docketTypeId, string description)
        : base(docketTypeId, description) { }
}

public abstract class Enumeration<TEnum, TId, TDescription> : IComparable
    where TEnum : Enumeration<TEnum, TId, TDescription>
{
    private static readonly Dictionary<TId, TEnum> _cache;

    static Enumeration()
    {
        Type t = typeof(TEnum);
        _cache = t.GetFields(BindingFlags.Public | BindingFlags.Static)
                  .Where(f => f.FieldType == t)
                  .Select(f => (TEnum)f.GetValue(null))
                  .ToDictionary(e => e.Id, e => e);
    }

    public static TEnum Resolve(TId id)
    {
        return _cache[id];
    }

    public TId Id { get; private set; }
    public TDescription Description { get; private set; }

    protected Enumeration(TId id, TDescription description)
    {
        Id = id;
        Description = description;
    }

    // IComparable
    public int CompareTo(object obj)
    {
        // TODO
        throw new NotImplementedException();
    }
}
公共类DocketType:枚举
{
公共静态只读DocketType撤回=
新的案卷类型(2,“撤回”);
公共静态只读DocketType安装=
新的文件类型(3,“安装”);
私有DocketType(int docketTypeId,字符串描述)
:base(docketTypeId,description){}
}
公共抽象类枚举:IComparable
其中TEnum:枚举
{
专用静态只读字典\u缓存;
静态枚举()
{
t型=类型(10μm);
_cache=t.GetFields(BindingFlags.Public | BindingFlags.Static)
.其中(f=>f.FieldType==t)
.选择(f=>(十微米)f.GetValue(null))
.ToDictionary(e=>e.Id,e=>e);
}
公共静态TEnum解析(TId id)
{
返回_缓存[id];
}
公共TId Id{get;private set;}
公共TDdescription Description{get;private set;}
受保护枚举(TId id、TDDescription描述)
{
Id=Id;
描述=描述;
}
//不可比
公共整数比较(对象对象对象)
{
//待办事项
抛出新的NotImplementedException();
}
}

如果您确实想强制另一个类的静态构造函数运行,可以使用。您可以从
枚举的静态构造函数调用它
,以便在您第一次对泛型类型的任何实例化使用静态方法时运行它:

static Enumeration()
{
    RuntimeHelpers.RunClassConstructor(typeof(TEnum).TypeHandle);
}

+1是一个非常好的主意,但我不希望有额外的
值实例。我已经没有了
static Enumeration()
{
    RuntimeHelpers.RunClassConstructor(typeof(TEnum).TypeHandle);
}