如何做才能让你的“枚举”有数据依赖于它?让你、如何做、才能、数据

2023-09-03 06:18:08 作者:爱上孤独

我有一票类,它可以有一个属性是一票的类型。如一致,3/4投票,一个简单多数,等每种类型都需要有一个与之关联的字符串,将描述表决类型(如一个简单的多数需要51%的通过等)。我需要通过这些票种/描述符合我的视图模型,以我的观点,然后我可以让我的下拉列表吧。

然后,当创建投票的形式提交我只需要绑定票型(无描述)的投票模式(这是视图模型的一部分​​)。

我只用C#很短的时间被我不太明白的枚举它是如何工作的。也许枚举是没有办法的办法去了解这一点。

 公共类VoteViewModel
{
    公共VoteViewModel()
    {
        投票=新投票();
    }

    公众投票投票{获得;组; }
    公众诠释EligibleVoters {获得;组; }
}
 

而这正是我将投入下拉。

 <节类=票式>
    <选择名称=>
        <期权价值=>选择投票类型< /选项>
    < /选择>
    <节类=票型信息>
        &其中,P类=票规则>向通过这个投票,合格选民中至少有51%必须投票批准它与LT; / P>
    < /节>
< /节>
 

解决方案 枚举

请注意我只显示字符串它可以​​是任何类型。在每一种情况下,我提到如何将其扩展为更多的值如果可能的话。

使用枚举作为一个键

您可以使用您的枚举类型作为键的字典(你想成为唯一的,因此使其在一些辅助类的静态和只读):

 私有静态只读字典< MyEnum,串> _dict =
{
    //使用字典的初始化
    {MyEnum.MyValue的文本myvalue的},
    {MyEnum.MyOtherValue,其他一些文字},
    {MyEnum.YetAnotherValue,别的东西}
}

公共静态只读字典< MyEnum,串>快译通
{
    得到
    {
        返回_dict;
    }
}
 

和访问相关的值:

 字符串文本=快译通[MyEnumEmu.MyValue]
 

或者用:

 文本字符串;
如果(Dict.TryGetValue(MyEnumEmu.MyValue,出文本))
{
    //它的价值
}
其他
{
    //它不具有值
}
 

这样,您就可以访问与该枚举值相关联的字符串。然后你就可以暴露你的字典,让您可以读取相应的值。

您将需要一个复杂类型,用于存储多个值。只需使用字符串自定义类型isntead。或者,如果可用,您可以使用元组

Accesing的词典可能意味着额外的烦恼,并希望这并不意味着一个线程的问题了。

Enum.GetName

您可以使用 Enum.GetName 阅读您的枚举值的名称:

 字符串文本= Enum.GetName(MyEnum.MyValue);
//文本将文本myvalue的

//要么
VAR一些= MyEnum.MyValue;
字符串文本= Enum.GetName(一般般);
 

注:的ToString()应太

可悲的是,这不会比字符串别的工作。

此外,它有一个你不能把任何文字有缺点(它必须是一个有效的标识符)。

自定义属性

您必须声明属性类型:

  [AttributeUsage(AttributeTargets.Field)
公共类EnumValueAttribute:System.Attribute
{
    公共只读字符串_value;

    公共字符串值
    {
        得到
        {
            返回_value;
        }
    }

    公共HelpAttribute附加(字符串值)//值是一个位置参数
    {
        //请注意:值可以为空...
        // ...但我们不希望在这里抛出异常
        _value =值;
    }
}
 

现在您应用属性的枚举:

 公开枚举MyEnum
{
    [EnumValue(以下简称文本myvalue的)
    myvalue的= 1,
    [EnumValue(其他一些文本)]
    MyOtherValue = 2,
    [EnumValue(别的东西)
    YetAnotherValue = 3
}
 

最后,你将需要阅读的属性后面:

 公共静态字符串的GetValue(MyEnumenumValue)
{
    字段信息fiendInfo = typeof运算(MyEnum).GetField(enumValue.ToString());
    如果(!的ReferenceEquals(fiendInfo,NULL))
    {
        [对象]属性= fieldInfo.GetCustomAttributes(typeof运算(EnumValueAttribute),TRUE);
        如果(的ReferenceEquals(属性,NULL)及!&安培; attributes.Length大于0)
        {
            返回((EnumValueAttribute)属性[0])值。
        }
    }
    //不是有效的值,或者没有足够的属性
    返回null;
}
 

现在,你可以把它叫做:

 字符串文本=的GetValue(MyEnum.MyValue);
//文本将文本myvalue的
//要么
VAR一些= MyEnum.MyValue;
字符串文本=的GetValue(一般般);
 

您可以添加更多的字段到你的属性类,并利用它们来传递你可能需要的任何其它的值。

但这需要反思的,如果你是在沙箱中运行它可能无法使用。它也将每次检索的属性,在proccess创造一些短暂的对象。

模拟枚举

您可以模拟一个枚举具有密封类,没有公共构造函数,并暴露了自身静态只读实例:

 公共密封类MyEnumEmu
{
    私人静态只读字符串myvalue的=新MyEnumEmu(以下简称文本myvalue的);
    私人静态只读字符串myOtherValue =新MyEnumEmu(其他一些文字);
    私人静态只读字符串yetAnotherValue =新MyEnumEmu(别的东西);

    公共静态MyEnumEmu myvalue的
    {
        得到
        {
            返回myvalue的;
        }
    }

    公共静态MyEnumEmu MyOtherValue
    {
        得到
        {
            返回myOtherValue;
        }
    }

    公共静态MyEnumEmu YetAnotherValue
    {
        得到
        {
            返回yetAnotherValue;
        }
    }

    私人字符串_value;

    私人MyEnumEmu(字符串值)
    {
        //真的,我们在此构造方法的调用者的控制权?
        // ...但是,只是为了好措施:
        如果(价值== NULL)
        {
            抛出新ArgumentNullException(价值);
        }
        其他
        {
            _value =值;
        }
    }

    公共字符串值
    {
        得到
        {
            返回_value;
        }
    }
}
 

使用它一如既往:

  VAR一些= MyEnumEmu.MyValue;
 

和访问相关的值:

 字符串文本= MyEnumEmu.MyValue.Value;
//文本将文本myvalue的
//要么
字符串文本= some.Value;
 

这是所有的更加灵活,你可以使用一个复杂的类型,而不是字符串或不是单个值传递更多添加额外的字段。

但...这是不是一个真正的枚举。

I have a Vote class and one of the properties it can have is a vote type. Such as unanimous, a 3/4 vote, a simply majority, etc. Each type needs to have a string associated with it which will describe the vote type (like "A simply majority requires 51% to pass" etc.). I need to pass these vote types/description in with my view model to my view and then I can make my drop down list with it.

Then, when the form that creates the vote is submitted I just need to bind the vote type (without description) to the Vote model (which is part of the view model).

I've only been using C# for a short time and I don't quite understand how the enums work in it. Perhaps enum is not the way to go about this.

public class VoteViewModel
{
    public VoteViewModel()
    {
        Vote = new Vote();
    }

    public Vote Vote { get; set; }
    public int EligibleVoters { get; set; }
}

And this is where I'll be putting the drop down.

<section class="vote-type">
    <select name="">
        <option value="">Select Vote Type</option>
    </select>
    <section class="vote-type-info">
        <p class="vote-rules">To pass this vote, at least 51% of Eligible Voters must vote to approve it.</p>
    </section>
</section>

解决方案

Please notice I'm only showing for strings for it could be any type. In each case I mention how to extend it for more values if possible.

Using the enum as a key

You can use your enum type as a key for a dictionary (you want to be unique, so make it static and readonly in some helper class):

private static readonly Dictionary<MyEnum, string> _dict =
{
    //Using dictionary initialization
    {MyEnum.MyValue, "The text for MyValue"},
    {MyEnum.MyOtherValue, "Some other text"},
    {MyEnum.YetAnotherValue, "Something else"}
}

public static readonly Dictionary<MyEnum, string> Dict
{
    get
    {
        return _dict;
    }
}

And access the associated value:

string text = Dict[MyEnumEmu.MyValue];

Or with:

string text;
if (Dict.TryGetValue(MyEnumEmu.MyValue, out text))
{
    //It has the value
}
else
{
    //It doesn't have the value
}

This way you can access a string that is associated with the enum value. Then you can expose your Dictionary so that you can read the corresponding values.

You will need a complex type for storing more than one value. Just use your custom type isntead of string. Or if available you can use Tuples.

Accesing the Dictionary may mean an extra annoyance and hopefully it will not mean a threading problem too.

Enum.GetName

You can use Enum.GetName to read the name of the values of your enum:

string text = Enum.GetName(MyEnum.MyValue);
//text will have the text "MyValue"

//or
var some = MyEnum.MyValue;
string text = Enum.GetName(some);

Note: ToString() should work too.

Sadly, this will not work for something else than the string.

Also it has the drawback that you cannot put any text there (it has to be a valid identifier).

Custom Attributes

You will have to declare an attribute type:

[AttributeUsage(AttributeTargets.Field)]
public class EnumValueAttribute : System.Attribute 
{
    public readonly string _value;

    public string Value
    {
        get
        {
            return _value;
        }
    }

    public HelpAttribute(string value)  // value is a positional parameter
    {
        //beware: value can be null...
        // ...but we don't want to throw exceptions here
        _value = value;
    }
}

Now you apply the attribute to your enum:

public enum MyEnum
{
    [EnumValue("The text for MyValue")]
    MyValue = 1,
    [EnumValue("Some other text")]
    MyOtherValue = 2,
    [EnumValue("Something else")]
    YetAnotherValue = 3
}

Lastly you will need to read the attribute back:

public static string GetValue(MyEnumenumValue)
{
    FieldInfo fiendInfo = typeof(MyEnum).GetField(enumValue.ToString());
    if (!ReferenceEquals(fiendInfo, null))
    {
        object[] attributes = fieldInfo.GetCustomAttributes(typeof(EnumValueAttribute), true);
        if (!ReferenceEquals(attributes, null) && attributes.Length > 0)
        {
            return ((EnumValueAttribute)attributes[0]).Value;
        }
    }
    //Not valid value or it didn't have the attribute
    return null;
}

Now you can call it:

string text = GetValue(MyEnum.MyValue);
//text will have the text "MyValue"
//or
var some = MyEnum.MyValue;
string text = GetValue(some);

You can add more fields to your attribute class and use them to pass any other value you may need.

But this requires reflexion, and it may not be available if you are running in a sandbox. Also it will retrieve the attributes each time, creating some short lived objects in the proccess.

Emulate Enum

You can emulate an enum with a sealed class that has no public constructor and exposes static readonly instances of itself:

public sealed class MyEnumEmu
{
    private static readonly string myValue = new MyEnumEmu("The text for MyValue");
    private static readonly string myOtherValue = new MyEnumEmu("Some other text");
    private static readonly string yetAnotherValue = new MyEnumEmu("Something else");

    public static MyEnumEmu MyValue
    {
        get
        {
            return myValue;
        }
    }

    public static MyEnumEmu MyOtherValue 
    {
        get
        {
            return myOtherValue;
        }
    }

    public static MyEnumEmu YetAnotherValue
    {
        get
        {
            return yetAnotherValue;
        }
    }

    private string _value;

    private MyEnumEmu(string value)
    {
        //Really, we are in control of the callers of this constructor...
        //... but, just for good measure:
        if (value == null)
        {
            throw new ArgumentNullException("value");
        }
        else
        {
            _value = value;
        }
    }

    public string Value
    {
        get
        {
            return _value;
        }
    }
}

Use it as always:

var some = MyEnumEmu.MyValue;

And access the associated value:

string text = MyEnumEmu.MyValue.Value;
//text will have the text "MyValue"
//or
string text = some.Value;

This is the more flexible of all, you can either use a complex type instead of string or add extra fields for passing more than a single value.

But... it is not really an enum.