如何为枚举char(1)数据库字段实现C#枚举?

时间:2022-09-02 13:21:48

OK, so I have a database field of type char(1) that has a small number of possible state codes (e.g. 'F'= Failure, 'U'=Unknown, etc.). I'd like to have a C# enum class that corresponds to these states. I can do:

好的,所以我有一个char(1)类型的数据库字段,它有少量可能的状态代码(例如'F'= Failure,'U'= Unknown等)。我想要一个与这些状态相对应的C#enum类。我可以:

public enum StatusCode : byte {
    Unknown = (byte) 'U',
    Failure = (byte) 'F',
    // etc.
}

So far so good. But in the DataTable returned from the database, the column values are System.Data.SqlTypes.SqlString instances. There are obviously some issues converting from a C# string (or even a C# char) to a C# byte (since C# char is really a UTF-16 codepoint). But in this case I know the values are constrained to a small set, and the code should throw an exception if a value outside this set comes through.

到现在为止还挺好。但是在从数据库返回的DataTable中,列值是System.Data.SqlTypes.SqlString实例。显然有一些问题从C#字符串(甚至是C#字符)转换为C#字节(因为C#char实际上是UTF-16代码点)。但在这种情况下,我知道值被约束为一个小集合,如果此集合之外的值通过,代码应抛出异常。

With that in mind, what's the best way of doing this? Is it safe to cast from a SqlString to a byte? Would Convert.ToByte() be better? Would it be better to simply use a switch/case construct to crosswalk the values into the enum?

考虑到这一点,最好的方法是什么?从SqlString转换为字节是否安全? Convert.ToByte()会更好吗?简单地使用开关/案例构造将值交叉到枚举中会更好吗?

I'm looking for the "best" way to do this, not only in terms of getting the right results but also for code clarity. I suppose I could also just use some constants like

我正在寻找“最好”的方法,不仅在获得正确的结果方面,而且在代码清晰度方面。我想我也可以使用一些常量

public const char UnknownStatus = 'U';
public const char FailureStatus = 'F';

But I'd rather use an enum if possible. Any thoughts?

但如果可能的话,我宁愿使用枚举。有什么想法吗?

Edit: To clarify what I want do do with this, I'm expecting to use these values frequently throughout my code. For example, I want to be able to do things like:

编辑:为了澄清我想要做什么,我希望在我的代码中经常使用这些值。例如,我希望能够做到这样的事情:

public void DoSomething(StatusCode currentStatus) {
    if(currentStatus == StatusCode.Failure) {
        throw new SomeException();
    }

    switch(currentStatus) {
        case StatusCode.Unknown:
            // do something
            break;
    }
}

And so forth. I particularly want to avoid things like:

等等。我特别想避免这样的事情:

public void DoSomething(char currentStatus) {
    if(currentStatus == 'F') {
        // do something
    }
}

Since in this case I'm using what amounts to "magic numbers" all over the place. In particular, this would make migrating to some other state-flagging system virtually impossible. Does that make sense?

因为在这种情况下,我正在使用相当于“神奇数字”的地方。特别是,这将使迁移到其他一些状态标记系统几乎是不可能的。那有意义吗?

7 个解决方案

#1


Maybe a "constant" object?

也许是一个“恒定”的对象?

public sealed class StatusCode {
    private char value;

    public static readonly StatusCode Unknown = new StatusCode('U');
    public static readonly StatusCode Failure = new StatusCode('F');

    private StatusCode(char v) {
        value = v;
    }

    public override string ToString() {
        return value.ToString();
    }

}

Then, later in your code, you could use it like an enum: StatusCode.Unknown. You could also provide an internal method to 'parse' a received value into an object of StatusCode.

然后,在代码中稍后,您可以像枚举一样使用它:StatusCode.Unknown。您还可以提供一种内部方法,将收到的值“解析”为StatusCode的对象。

#2


Skip to edit Have you tried this (which doesn't work as you've checked and commented):

跳到编辑您是否尝试过此操作(这不会像您检查和评论时那样有效):

public enum StatusCode : char
{
    Failure = 'F',
    Unknown = 'U',
    ...
}

EDIT - correct solution
or this (maybe even try with a struct):

编辑 - 正确的解决方案或这个(甚至尝试使用结构):

public sealed class StatusCode
{
    public static readonly char Failure = 'F';
    public static readonly char Unknown = 'U';
    ...
    public char Value { get; set; }
}

your code you provided would work like this:

您提供的代码将如下工作:

public void DoSomething(StatusCode currentStatus) {
    if(currentStatus.Value == StatusCode.Failure) {
        throw new SomeException();
    }

    switch(currentStatus.Value) {
        case StatusCode.Unknown:
            // do something
            break;
    }
}

If you don't like to use Value property you can always implement implicit equality operator between StatusCode and char types. In that case, your code wouldn't change a bit.

如果您不喜欢使用Value属性,则可以始终在StatusCode和char类型之间实现隐式相等运算符。在这种情况下,您的代码不会改变一点。

#3


If you're on .NET 2.0 and higher, you could implement this using a generic dictionary:

如果您使用的是.NET 2.0及更高版本,则可以使用通用字典实现此目的:

Dictionary<char,string> statusCode = new Dictionary<char,string>();
statusCode.Add('U', "Unknown");
statusCode.Add('F', "Failure");

or alternatively:

Dictionary<char,StatusCode> statusCode = new Dictionary<char,StatusCode>();
statusCode.Add('U', StatusCode.Unknown);
statusCode.Add('F', StatusCode.Failure);

and you could access the string representation for a given code like so:

你可以访问给定代码的字符串表示,如下所示:

string value = statusCode['A'];

or

StatusCode myCode = statusCode['A'];

and so on. You would have to fill that dictionary from the database values, or from some kind of a config file or something.

等等。您必须从数据库值或某种配置文件或其他东西填充该字典。

Marc

#4


Would something like this work for you?

这样的事情对你有用吗?

public Enum StatusCode : int{
   [StringValue("U")]
   Unknown =0,
   [StringValue["F"]
   Failuer=1
}

#5


If you have a table called StatusCode which includes an integer primary key then you could use that as your identifier as well as hook it into your logic. And in that case, the enum would be the best thing to use. Though i'm not sure if this is feasible for you.

如果你有一个名为StatusCode的表,它包含一个整数主键,那么你可以使用它作为你的标识符,并将它挂钩到你的逻辑中。在这种情况下,枚举将是最好的使用。虽然我不确定这对你是否可行。

#6


One option is to setup your enum with identical names to the values in your database, such as:

一种选择是使用与数据库中的值相同的名称设置枚举,例如:

enum StatusCode
{
    /// <summary>Unknown</summary>
    U = 0,
    /// <summary>Failure</summary>
    F,
    /// <summary>Etc</summary>
    E
}

Then use a static method to convert char values to an enumerated value

然后使用静态方法将char值转换为枚举值

    private StatusCode CharToEnum(string statusCodeChar)
    {
        foreach (FieldInfo fi in typeof(StatusCode).GetFields())
        {
            if (fi.Name == statusCodeChar) return (StatusCode)fi.GetValue(null);
        }

        return StatusCode.U;
    }

#7


Short and sweet my man.. Does everything you need it to. You shouldn't need to use enum because you don't need it to assign an internal value to your possible states, you already know the values to your states.

我的男人简短而甜蜜..你需要的一切都是如此。您不需要使用枚举,因为您不需要它为您的可能状态分配内部值,您已经知道状态的值。

public sealed class StatusCode
{
    public const string Unknown= "U";
    public const string Failure= "F";
    public const string Success= "S";
}

#1


Maybe a "constant" object?

也许是一个“恒定”的对象?

public sealed class StatusCode {
    private char value;

    public static readonly StatusCode Unknown = new StatusCode('U');
    public static readonly StatusCode Failure = new StatusCode('F');

    private StatusCode(char v) {
        value = v;
    }

    public override string ToString() {
        return value.ToString();
    }

}

Then, later in your code, you could use it like an enum: StatusCode.Unknown. You could also provide an internal method to 'parse' a received value into an object of StatusCode.

然后,在代码中稍后,您可以像枚举一样使用它:StatusCode.Unknown。您还可以提供一种内部方法,将收到的值“解析”为StatusCode的对象。

#2


Skip to edit Have you tried this (which doesn't work as you've checked and commented):

跳到编辑您是否尝试过此操作(这不会像您检查和评论时那样有效):

public enum StatusCode : char
{
    Failure = 'F',
    Unknown = 'U',
    ...
}

EDIT - correct solution
or this (maybe even try with a struct):

编辑 - 正确的解决方案或这个(甚至尝试使用结构):

public sealed class StatusCode
{
    public static readonly char Failure = 'F';
    public static readonly char Unknown = 'U';
    ...
    public char Value { get; set; }
}

your code you provided would work like this:

您提供的代码将如下工作:

public void DoSomething(StatusCode currentStatus) {
    if(currentStatus.Value == StatusCode.Failure) {
        throw new SomeException();
    }

    switch(currentStatus.Value) {
        case StatusCode.Unknown:
            // do something
            break;
    }
}

If you don't like to use Value property you can always implement implicit equality operator between StatusCode and char types. In that case, your code wouldn't change a bit.

如果您不喜欢使用Value属性,则可以始终在StatusCode和char类型之间实现隐式相等运算符。在这种情况下,您的代码不会改变一点。

#3


If you're on .NET 2.0 and higher, you could implement this using a generic dictionary:

如果您使用的是.NET 2.0及更高版本,则可以使用通用字典实现此目的:

Dictionary<char,string> statusCode = new Dictionary<char,string>();
statusCode.Add('U', "Unknown");
statusCode.Add('F', "Failure");

or alternatively:

Dictionary<char,StatusCode> statusCode = new Dictionary<char,StatusCode>();
statusCode.Add('U', StatusCode.Unknown);
statusCode.Add('F', StatusCode.Failure);

and you could access the string representation for a given code like so:

你可以访问给定代码的字符串表示,如下所示:

string value = statusCode['A'];

or

StatusCode myCode = statusCode['A'];

and so on. You would have to fill that dictionary from the database values, or from some kind of a config file or something.

等等。您必须从数据库值或某种配置文件或其他东西填充该字典。

Marc

#4


Would something like this work for you?

这样的事情对你有用吗?

public Enum StatusCode : int{
   [StringValue("U")]
   Unknown =0,
   [StringValue["F"]
   Failuer=1
}

#5


If you have a table called StatusCode which includes an integer primary key then you could use that as your identifier as well as hook it into your logic. And in that case, the enum would be the best thing to use. Though i'm not sure if this is feasible for you.

如果你有一个名为StatusCode的表,它包含一个整数主键,那么你可以使用它作为你的标识符,并将它挂钩到你的逻辑中。在这种情况下,枚举将是最好的使用。虽然我不确定这对你是否可行。

#6


One option is to setup your enum with identical names to the values in your database, such as:

一种选择是使用与数据库中的值相同的名称设置枚举,例如:

enum StatusCode
{
    /// <summary>Unknown</summary>
    U = 0,
    /// <summary>Failure</summary>
    F,
    /// <summary>Etc</summary>
    E
}

Then use a static method to convert char values to an enumerated value

然后使用静态方法将char值转换为枚举值

    private StatusCode CharToEnum(string statusCodeChar)
    {
        foreach (FieldInfo fi in typeof(StatusCode).GetFields())
        {
            if (fi.Name == statusCodeChar) return (StatusCode)fi.GetValue(null);
        }

        return StatusCode.U;
    }

#7


Short and sweet my man.. Does everything you need it to. You shouldn't need to use enum because you don't need it to assign an internal value to your possible states, you already know the values to your states.

我的男人简短而甜蜜..你需要的一切都是如此。您不需要使用枚举,因为您不需要它为您的可能状态分配内部值,您已经知道状态的值。

public sealed class StatusCode
{
    public const string Unknown= "U";
    public const string Failure= "F";
    public const string Success= "S";
}