以与Enum相同的方式将字符串值存储为常量

时间:2021-06-19 10:08:07

I know there is a way to make enum work for string types with conversions galore - the code doesn't look pretty.

我知道有一种方法可以让enum适用于转换丰富的字符串类型 - 代码看起来不漂亮。

Does anyone know of any way to have something like this:

有谁知道有这样的事情:

    public SOMESTRUCTURE SessionKeys : string
{
    value1 = "value1key",
    value2 = "value2key",
    name = "name"
}

so later in my code I could refer to it as:

所以稍后在我的代码中我可以将其称为:

SessionKeys.value1

4 个解决方案

#1


This is about the best I've come up with. (I haven't compiled it, so the syntax may be off.)

这是我提出的最好的。 (我没有编译它,所以语法可能会关闭。)

public static class SessionKeys
{
    public const string Value1 = "Value1";
    public const string Value2 = "Value2";
    ...
}

#2


Using C# 2.0 - I believe the best option is to use a static class with constants for your values, as suggested by John Fisher.

使用C#2.0 - 我认为最好的选择是使用一个静态类,其值为常量,如John Fisher所建议的那样。

If you can use C# 3.0, you could use a standard enum, and a simple extension method to handle the conversion in a less objectionable manner.

如果您可以使用C#3.0,则可以使用标准枚举和简单的扩展方法以较少令人反感的方式处理转换。

#3


See my answer here:
Getting static field values of a type using reflection

请在此处查看我的答案:使用反射获取类型的静态字段值

The difference between this and John Fisher's answer is that you can pass SessionKeys as function parameters and get the enum-like semantics you want.

这和John Fisher的答案之间的区别在于你可以将SessionKeys作为函数参数传递,并获得你想要的类似enum的语义。

The previous question asked for VB.Net, but a C# port shouldn't be that hard. In fact, here (untested):

上一个问题要求VB.Net,但C#端口不应该那么难。事实上,这里(未经测试):

public interface ICustomEnum<T>
{
    ICustomEnum<T> FromT(T value);
    T Value { get; }

    // Implement using a sealed class with a private constructor 
    // that accepts and sets the Value property, 
    // one shared readonly property for each desired value in the enum,
    // and implicit conversions to and from T.
    // Then see this link to get intellisense support
    // that exactly matches a normal enum:
    // https://*.com/questions/102084/hidden-features-of-vb-net/102217#102217
    // Note that the completion list only works for VB.
}

/// <completionlist cref="SessionKeys"/>
public sealed SessionKeys: ICustomEnum<string>
{
    private string _value;
    public string Value { get { return _value; } } 

    private SessionKeys(string value)
    {
        _value = value;
    }

    private static SessionKeys _value1 = new MyStringEnum("value1key");
    public static SessionKeys value1 { get { return _value1;} } 

    private static MyStringEnum _value2 = new MyStringEnum("value2key");
    public static MyStringEnum value2 { get { return _value2;} } 

    public static ICustomEnum<string> FromString(string value) 
    {
        // use reflection or a dictionary here if you have a lot of values
        switch( value )
        {
            case "value1key":
                return value1;
            case "value2key":
                return value2;
            default:
                return null; //or throw an exception
        }
    }

    public ICustomEnum<string> FromT(string value) 
    {
        return FromString(value);
    }

    public static implicit operator string(SessionKeys item)
    {
        return item.Value;
    }

    public static implicit operator SessionKeys(string value)
    {
        return FromString(value);
    }
}

You don't really need the interface, but I keep it to remind me how to implement them.

你真的不需要界面,但我保留它以提醒我如何实现它们。

#4


The thing is that an enum isn't just a static class with a bunch of public numerical constants. An enum is a Type. With constants you lose type safety. You can achieve type safety if you make the static members of your class the same type as the class.

问题是枚举不仅仅是一个带有一堆公共数值常量的静态类。枚举是一种类型。使用常量会丢失类型安全性。如果使类的静态成员与类的类型相同,则可以实现类型安全。

public sealed class SessionKey
{
    private _value; 
    private SessionKey( string value )
    {
        _value = value;
    }

    public string Value { get return _value; }

    public static readonly SessionKey Value1 = new SessionKey( "Value1" );
    public static readonly SessionKey Value2 = new SessionKey( "Value2" );
}

public class Something
{
    /* stuff */
    public void Foo( SessionKey sessionKey )
    {
        switch( sessionKey.Value )
        {
            case SessionKey.Value1.Value:
                DoBaz();
                break;
            case SessionKey.Value2.Value:
                DoBop();
                break;
            default:
                DoBar();
        }
    }   

    /* other stuff */
}

#1


This is about the best I've come up with. (I haven't compiled it, so the syntax may be off.)

这是我提出的最好的。 (我没有编译它,所以语法可能会关闭。)

public static class SessionKeys
{
    public const string Value1 = "Value1";
    public const string Value2 = "Value2";
    ...
}

#2


Using C# 2.0 - I believe the best option is to use a static class with constants for your values, as suggested by John Fisher.

使用C#2.0 - 我认为最好的选择是使用一个静态类,其值为常量,如John Fisher所建议的那样。

If you can use C# 3.0, you could use a standard enum, and a simple extension method to handle the conversion in a less objectionable manner.

如果您可以使用C#3.0,则可以使用标准枚举和简单的扩展方法以较少令人反感的方式处理转换。

#3


See my answer here:
Getting static field values of a type using reflection

请在此处查看我的答案:使用反射获取类型的静态字段值

The difference between this and John Fisher's answer is that you can pass SessionKeys as function parameters and get the enum-like semantics you want.

这和John Fisher的答案之间的区别在于你可以将SessionKeys作为函数参数传递,并获得你想要的类似enum的语义。

The previous question asked for VB.Net, but a C# port shouldn't be that hard. In fact, here (untested):

上一个问题要求VB.Net,但C#端口不应该那么难。事实上,这里(未经测试):

public interface ICustomEnum<T>
{
    ICustomEnum<T> FromT(T value);
    T Value { get; }

    // Implement using a sealed class with a private constructor 
    // that accepts and sets the Value property, 
    // one shared readonly property for each desired value in the enum,
    // and implicit conversions to and from T.
    // Then see this link to get intellisense support
    // that exactly matches a normal enum:
    // https://*.com/questions/102084/hidden-features-of-vb-net/102217#102217
    // Note that the completion list only works for VB.
}

/// <completionlist cref="SessionKeys"/>
public sealed SessionKeys: ICustomEnum<string>
{
    private string _value;
    public string Value { get { return _value; } } 

    private SessionKeys(string value)
    {
        _value = value;
    }

    private static SessionKeys _value1 = new MyStringEnum("value1key");
    public static SessionKeys value1 { get { return _value1;} } 

    private static MyStringEnum _value2 = new MyStringEnum("value2key");
    public static MyStringEnum value2 { get { return _value2;} } 

    public static ICustomEnum<string> FromString(string value) 
    {
        // use reflection or a dictionary here if you have a lot of values
        switch( value )
        {
            case "value1key":
                return value1;
            case "value2key":
                return value2;
            default:
                return null; //or throw an exception
        }
    }

    public ICustomEnum<string> FromT(string value) 
    {
        return FromString(value);
    }

    public static implicit operator string(SessionKeys item)
    {
        return item.Value;
    }

    public static implicit operator SessionKeys(string value)
    {
        return FromString(value);
    }
}

You don't really need the interface, but I keep it to remind me how to implement them.

你真的不需要界面,但我保留它以提醒我如何实现它们。

#4


The thing is that an enum isn't just a static class with a bunch of public numerical constants. An enum is a Type. With constants you lose type safety. You can achieve type safety if you make the static members of your class the same type as the class.

问题是枚举不仅仅是一个带有一堆公共数值常量的静态类。枚举是一种类型。使用常量会丢失类型安全性。如果使类的静态成员与类的类型相同,则可以实现类型安全。

public sealed class SessionKey
{
    private _value; 
    private SessionKey( string value )
    {
        _value = value;
    }

    public string Value { get return _value; }

    public static readonly SessionKey Value1 = new SessionKey( "Value1" );
    public static readonly SessionKey Value2 = new SessionKey( "Value2" );
}

public class Something
{
    /* stuff */
    public void Foo( SessionKey sessionKey )
    {
        switch( sessionKey.Value )
        {
            case SessionKey.Value1.Value:
                DoBaz();
                break;
            case SessionKey.Value2.Value:
                DoBop();
                break;
            default:
                DoBar();
        }
    }   

    /* other stuff */
}