c# - 你如何制作一个绑定(bind)了数据的 'enum'?

标签 c# .net asp.net-mvc enums

我有一个 Vote 类,它可以拥有的属性之一是投票类型。例如一致、3/4 投票、简单多数等。每种类型都需要有一个与之关联的字符串来描述投票类型(例如“简单多数需要 51% 才能通过”等)。我需要将这些投票类型/描述与我的 View 模型一起传递到我的 View ,然后我可以用它制作我的下拉列表。

然后,当创建投票的表单被提交时,我只需要将投票类型(没有描述)绑定(bind)到投票模型(它是 View 模型的一部分)。

我使用 C# 的时间很短,我不太了解其中的枚举是如何工作的。也许枚举不是解决这个问题的方法。

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

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

这就是我要放置下拉菜单的地方。

<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>

最佳答案

请注意我只显示字符串,因为它可以是任何类型。在每种情况下,我都会提到如何尽可能扩展它以获得更多值。


使用枚举作为键

你可以使用你的枚举类型作为字典的键(你想要是唯一的,所以在一些帮助类中将它设为静态和只读):

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;
    }
}

并访问关联值:

string text = Dict[MyEnum.MyValue];

或者用:

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

这样您就可以访问与枚举值关联的字符串。然后您可以公开您的字典,以便您可以读取相应的值。

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

访问 Dictionary 可能意味着额外的烦恼,希望它不会也意味着线程问题。


枚举.GetName

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

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

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

注意:ToString() 也应该有效。

遗憾的是,这对字符串以外的东西不起作用。

它还有一个缺点,就是你不能在其中放置任何文本(它必须是一个有效的标识符)。


自定义属性

您必须声明一个属性类型:

[AttributeUsage(AttributeTargets.Field)]
public class EnumValueAttribute : System.Attribute 
{
    public readonly string _value;
    public string Value
    {
        get
        {
            return _value;
        }
    }
    public EnumValueAttribute(string value)  // value is a positional parameter
    {
        //beware: value can be null...
        // ...but we don't want to throw exceptions here
        _value = value;
    }
}

现在您将该属性应用于您的枚举:

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

最后你需要读回属性:

public static string GetValue(MyEnum enumValue)
{
    FieldInfo fieldInfo = typeof(MyEnum).GetField(enumValue.ToString());
    if (!ReferenceEquals(fieldInfo, 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;
}

现在你可以调用它了:

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

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

但这需要反射(reflection),如果你在沙箱中运行,它可能不可用。此外,它每次都会检索属性,在过程中创建一些短暂的对象。


模拟枚举

您可以使用密封类模拟枚举,该类没有公共(public)构造函数并公开其自身的静态只读实例:

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;
        }
    }
}

一如既往地使用它:

var some = MyEnumEmu.MyValue;

并访问关联值:

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

这是最灵活的一种,您可以使用复杂类型而不是字符串,或者添加额外的字段来传递多个值。

但是...它并不是真正的枚举。

关于c# - 你如何制作一个绑定(bind)了数据的 'enum'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11200286/

相关文章:

c# - 使用循环和 "clean"代码在多个级别添加多个子项

c# - 识别 Sharepoint 文档库中的 "Forms"文件夹

c# - 在某些情况下,OptimisticConcurrencyException 在 Entity Framework 中不起作用

c# - Linq 中的排序和唯一记录

c# - 入口后面带有 Azure OAuth 的 ASP.NET Core MVC 进入无限登录循环

c# - 如何将字符串转换为 base64 字节数组,这有效吗?

c# - .NET SSH 端口转发

.net - 日期时间格式与 SQL Server 中的格式不匹配

asp.net-mvc - 路径 '/Login/Index' 的 Controller 未找到或未实现 IController

asp.net-mvc - 如何从 MVC 5 应用程序发送电子邮件