C# 类型安全且开发人员友好的列表/集合技术

发布于 2024-09-06 01:53:26 字数 451 浏览 5 评论 0原文

我正在用 sp 调用的结果填充“字典”。键是字段名称,值是 sp 为该字段返回的任何值。这一切都很好,但出于安全和文档原因,我希望开发人员有一个预定义的密钥列表来访问此列表。我想做的是将枚举之类的东西作为字典的键,以便开发人员可以安全地访问列表,但仍然能够使用字符串键值访问字典。

我希望有一个可以使用枚举键和字符串键访问的字符串值列表。请确保任何建议都易于实施,这不是我愿意花费大量开销来实施的事情。

笔记: 我希望有一个键来驱动这个而不是一个枚举声明和一个列表声明,因为我将维护两个键列表,只是格式略有不同。

更新: 让我澄清一下我想要一个字符串键的原因,我在一次情况下使用这个列表来在具有类似 ##keyName## 的较大字符串中进行替换。所以我需要能够根据 #### 中的内容从我的字典中获取值。如果我使用枚举作为密钥,我不知道该怎么做。如果我可以将字符串“keyName”映射到 enum.keyName 那么我的问题就解决了。

I am populating a "Dictionary" with the results of an sp call. The key is the field name and the value is whatever value the sp returns for the field. This is all well and good but I'd like developers to have a predefined list of keys to access this list, for safety and documentation reasons. What I'd like to do is have something like an enum as a key for the dictionary so developers can safely access the list, but still have the ability to access the dictionary with a string key value.

I am hoping to have a list of string values that I can access with an enum key AND a string key. Please make sure any suggestions are simple to implement, this is not the kind of thing I'm willing to build a lot of overhead to implement.

NOTE:
I'd like there to be one key that drives this not one enum declaration and one List declaration in that I'd be maintaining two lists of keys, just in slightly different formats.

UPDATE:
Let me clarify the reason I'd like a string key, I am using this list of stuff in once case to do replacements in a larger string that has something like ##keyName##. So i need to be able get values out of my dictionary based on what's in the ####. I don't know how to do that if I'm using an enum as my key. if I could map the string "keyName" to enum.keyName then my problems are solved.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

怀里藏娇 2024-09-13 01:53:26

我只想创建一个包含常量字符串而不是枚举的类。

class Keys
{
    public const string Key1 = "Key1";
    public const string Key2 = "Key2";
}

这样你就不必对字典做任何事情,但仍然拥有“建议的键”。

I would just create a class containing constant strings instead of enums.

class Keys
{
    public const string Key1 = "Key1";
    public const string Key2 = "Key2";
}

This way you don't have to do anything with the dictionary, but still have your "suggested keys".

冷夜 2024-09-13 01:53:26

如果您不寻求大量开销,那么可以使用扩展方法。

If your not looking for a lot of overhead, then using Extension methods is a possibility.

疯狂的代价 2024-09-13 01:53:26

听起来您正在尝试复制类型化数据集、LINQ to SQL 甚至普通旧 DTO 中已经存在的功能(也许需要 Automapper 的帮助)。开发人员会发现更容易使用已经熟悉的结构,如数据表或对象属性

Sounds like you are trying to replicate functionality already present in typed datasets, LINQ to SQL or even plain old DTOs (perhaps with some help from Automapper). Developers will find it easier to work with already familiar constructs like datatables or object properties

做个ˇ局外人 2024-09-13 01:53:26

任何枚举都可以使用 ToString 转换为字符串。因此,您可以编写一个索引器来接受任何对象并对其调用 ToString。对于字符串来说,这是一个空操作。

编辑

从 meiscooldude 窃取一个想法:

public static class EnumDictExt
{
    public static TValue Lookup<TValue, TEnum>(this IDictionary<string, TValue> dict, TEnum e)
            where TEnum : struct, IComparable, IFormattable, IConvertible
        { return dict[e.ToString()]; }
}

Any enum can be converted to a string with ToString. Therefore, you can write an indexer that takes any object and calls ToString on it. For a string, this is a no-op.

edit

To steal an idea from meiscooldude:

public static class EnumDictExt
{
    public static TValue Lookup<TValue, TEnum>(this IDictionary<string, TValue> dict, TEnum e)
            where TEnum : struct, IComparable, IFormattable, IConvertible
        { return dict[e.ToString()]; }
}
宫墨修音 2024-09-13 01:53:26

您可以尝试如下操作:

public enum MyKeys
{
    FirstKey,
    SecondKey,
    ThirdKey
}

然后在代码中的其他位置:

var dict = new Dictionary<MyKeys, string>();

dict.Add(MyKeys.FirstKey, "something");
dict.Add(MyKeys.SecondKey, "something else");
dict.Add(MyKeys.ThirdKey, "something else again");

// And then to access them, you can use
var stringVal = dict[MyKeys.FirstKey];
var secondVal = dict[(MyKeys)Enum.Parse(typeof(MyKeys), "secondkey", true)];

You could try something like the following:

public enum MyKeys
{
    FirstKey,
    SecondKey,
    ThirdKey
}

And then elsewhere in your code:

var dict = new Dictionary<MyKeys, string>();

dict.Add(MyKeys.FirstKey, "something");
dict.Add(MyKeys.SecondKey, "something else");
dict.Add(MyKeys.ThirdKey, "something else again");

// And then to access them, you can use
var stringVal = dict[MyKeys.FirstKey];
var secondVal = dict[(MyKeys)Enum.Parse(typeof(MyKeys), "secondkey", true)];
不爱素颜 2024-09-13 01:53:26

您可以将字典包装在自定义类中,并向该类添加两个索引器,一个用于字符串访问,另一个用于枚举访问

You can wrap a Dictionary in a custom class and add two indexers to that class one for string access and the other one for enum access

苄①跕圉湢 2024-09-13 01:53:26

正如其他人所说,您可以创建两个索引器。但为了鼓励使用枚举并阻止使用字符串,请将枚举设为索引器并将字符串 api 命名为“GetTheValueOfThisElementWhichCanBeUnsafe”或类似名称(您明白了...)。

尽管我很懒,但如果两者都是索引器,我就不会在意,而是一直使用字符串版本。但如果 API 以某种方式向我咆哮,我至少会看到代码中的含义。

Like others said, you can create two indexers. But to encourage the enum and to discourage to string, make the enum the indexer and name the string api something like "GetTheValueOfThisElementWhichCanBeUnsafe" or similar (you get the idea...).

Lazy as I am, if both are indexers I could not care less but use the string version all the time. But if the API barks at me in a certain way, I at least see the implications in the code.

宫墨修音 2024-09-13 01:53:26

如果我理解正确的话,我最近对从服务器接收/发送到服务器的数据包做了类似的事情。数据包采用Key: Value\n 形式,并由表示其数据包类型的特殊键/值对定义(Action: Login,在本例中如下。请参阅< a href="http://www.voip-info.org/wiki/view/Asterisk+manager+API" rel="nofollow noreferrer">Asterisk API 以获取更多参考。)我解析了数据包类型,根据预期的键生成类,如下所示:

public abstract class Packet
{
    private Dictionary<string, string> _dictionary =
        new Dictionary<string, string>();

    public string this[string key]
    {
        get
        {
            if (_dictionary.ContainsKey(key))
            {
                return _dictionary[key];
            }
            else { return ""; }
        }
        set { _dictionary[key] = value; }
    }

    public abstract PacketType Type { get; }
}

public class LoginPacket : Packet
{
    public override PacketType Type
    { get { return PacketType.Action; } }

    public string Username
    {
        get { return this["Username"]; }
        set { this["Username"] = value; }
    }
    public string Password
    {
        get { return this["Password"]; }
        set { this["Password"] = value; }
    }
    public int Status // Example: Not an actual key in Login in the Asterisk API
    {
        get { return int.Parse(this["Status"]); }
        set { this["Status"] = value.ToString(); }
    }
}

这创建了一种强类型字典,您可以这样做:

LoginPacket packet = new LoginPacket
{
    Username = "User",
    Password = "user",
    Status = 123
};
Console.WriteLine(packet.Username); // Is equal to:
Console.WriteLine(packet["Username"]);

然后像任何其他类似字典的类一样处理packet,您可以扩展它,这样Packet 实现 IDictionary,或者走另一个方向并使 this[string key] getset 受到保护,以便使用有效密钥。

If I understand you correctly, I recently did something similar with packets I received from/sent to a server. The packets were in form Key: Value\n and defined by a special key/value pair denoting its packet type (Action: Login, in this case below. See the Asterisk API for more reference.) I parsed the packet type out, generated classes based on the expected keys, as such:

public abstract class Packet
{
    private Dictionary<string, string> _dictionary =
        new Dictionary<string, string>();

    public string this[string key]
    {
        get
        {
            if (_dictionary.ContainsKey(key))
            {
                return _dictionary[key];
            }
            else { return ""; }
        }
        set { _dictionary[key] = value; }
    }

    public abstract PacketType Type { get; }
}

public class LoginPacket : Packet
{
    public override PacketType Type
    { get { return PacketType.Action; } }

    public string Username
    {
        get { return this["Username"]; }
        set { this["Username"] = value; }
    }
    public string Password
    {
        get { return this["Password"]; }
        set { this["Password"] = value; }
    }
    public int Status // Example: Not an actual key in Login in the Asterisk API
    {
        get { return int.Parse(this["Status"]); }
        set { this["Status"] = value.ToString(); }
    }
}

This creates a sort of strongly-typed dictionary, and you can do:

LoginPacket packet = new LoginPacket
{
    Username = "User",
    Password = "user",
    Status = 123
};
Console.WriteLine(packet.Username); // Is equal to:
Console.WriteLine(packet["Username"]);

Then handle packet like any other dictionary-like class, You could extend this so that Packet implements IDictionary, or go the other direction and make this[string key] get or set protected so that only valid keys are used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文