簡體   English   中英

用於標志的自定義枚舉基礎 class

[英]Custom enum base class for flags

我正在按照Microsoft 的建議制作自定義枚舉 class,但努力制作支持標志樣式枚舉的版本。

當嘗試將兩個實例按位或一起創建一個不存在的新實例時,就會出現問題。

public abstract class Enumeration<TEnum>
    where TEnum : Enumeration<TEnum>
{
    public int Id { get; private set; }
    public string Name { get; private set; }

    protected Enumeration(int id, string name) => (Id, Name) = (id, name);

    public override string ToString() => Name;

    public static IEnumerable<TEnum> GetAll() =>
        typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
                 .Where(info => enumerationType.IsAssignableFrom(info.FieldType))
                 .Select(f => f.GetValue(null))
                 .Cast<T>();

    public static Enumeration<TEnum> operator |(Enumeration<TEnum> left, Enumeration<TEnum> right)
    {
        // This is the problem method!
        // I can obviously bitwise or together the two values, but how do I create an instance
        // of TEnum from here so that is has a valid name?

        // For instance, Colors.Red | Colors.Blue would need to be an instance where
        // Id == (1 << 0 | 1 << 1) and Name == "Red, Blue".
    }

    // Other utility methods ...
}

public class Colors : Enumeration<Colors>
{
    public static readonly Colors Red = new Colors(1 << 0, "Red");
    public static readonly Colors Blue = new Colors(1 << 1, "Blue");
    public static readonly Colors Green = new Colors(1 << 2, "Green");

    public Colors(int id, string name) : base(id, name) { }
}

如果這是一個 xy 問題,我也很樂意聽取其他想法。

問題將始終是您無法從本地抽象基礎 class 內部構造Colors的實例。 即,您可以將泛型約束為具有new()但不具有特定的構造函數,例如new(int, string)

因此,一種選擇是在具體 class 本身內部定義(並為枚舉的每個實例重新定義)運算符

public class Colors : Enumeration<Colors>
{
    public static readonly Colors Red = new Colors(1 << 0, "Red");
    public static readonly Colors Blue = new Colors(1 << 1, "Blue");
    public static readonly Colors Green = new Colors(1 << 2, "Green");

    public Colors(int id, string name) : base(id, name) { }
    
    public static Colors operator |(Colors left, Colors right)
    {
        return new Colors(left.Id | right.Id, $"{left.Name}, {right.Name}");
    }
}

它工作的實時示例,但我懷疑這不是您想要做的: https://dotnetfiddle.net/KBQEt4

另一種選擇是為每個枚舉提供創建自身的智能(即,繞過缺乏特定的構造函數約束),然后您可以在基礎 class 上使用運算符:

public abstract class Enumeration<TEnum>
    where TEnum : Enumeration<TEnum>
{
    public int Id { get; private set; }
    public string Name { get; private set; }
    

    protected Enumeration(int id, string name) => (Id, Name) = (id, name);

    public override string ToString() => Name;

    public static Enumeration<TEnum> operator |(Enumeration<TEnum> left, Enumeration<TEnum> right)
    {
        return left.Create(left.Id | right.Id, $"{left.Name}, {right.Name}");
    }
    
    protected abstract Enumeration<TEnum> Create(int id, string name);
    

    // Other utility methods ...
}

public class Colors : Enumeration<Colors>
{
    public static readonly Colors Red = new Colors(1 << 0, "Red");
    public static readonly Colors Blue = new Colors(1 << 1, "Blue");
    public static readonly Colors Green = new Colors(1 << 2, "Green");

    public Colors(int id, string name) : base(id, name) { }
    
    protected override Enumeration<Colors> Create(int id, string name) => new Colors(id,name);
    
}

現場示例: https://dotnetfiddle.net/8ZBQqk

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM