如何返回未知类型的值?

时间:2019-03-11 13:49:28

标签: c#

我前面有一个非常抽象问题。

我有一个类型为Dictionary<string, object>的公共属性的类,该词典的工作是保存自定义用户设置及其值。

对设置没有任何限制,但通常它们类似于:
“亮度”,100
“连接,“ TCP”

因此,当我实例化此类时,其字典属性将由设置名称及其对应的值填充。

问题在于获取值。
因为值可以是整数,字符串等,所以它们以object的形式存储在字典中,但是我需要将它们作为具体类型进行检索。

虽然我可以使用dict["Brightness"].GetType()来查找类型或使用模式匹配,但是在找出要使用的方法返回类型时遇到了麻烦。

我认为,也许我可以为每种类型使用单独的“结果”属性,然后根据值的类型将相应的值分配给正确的属性,例如,如果“亮度”为100,则有一个方法测试“亮度”值的类型,并在看到它为int时执行类似的操作

int resultInt;
resultInt = (int)dict["Brightness"];

但是有些东西告诉我这很丑,而且有更好的方法。
此外,这不是线程安全的。

有关该计划目的的其他信息:
该程序的想法是基本上能够存储用于不同系统的大量设置及其值。它们始终处于键-值关系中,键是唯一的,值可以是任何值。它们可以是字符串,整数,浮点数,十进制等。程序的目的是通过某种方式进行用户自定义。
我的意思是-用户输入要存储的设置。他输入的内容将成为程序将使用的可能设置的完整列表。然后,他为自己拥有的每个系统或“设备”输入这些设置的值。因此,例如,他说“我有一台电脑和一部智能手机”。在程序中输入设置“亮度”和“ CPU”。现在,程序知道他配置的所有系统都将具有这两个设置,并且它们可能具有不同的值。
因此用户可以说“我希望智能手机的屏幕亮度为80%”。因此,他输入了与他的智能手机相对应的整数“ 80”作为“亮度”的值。同样,他可以为家用计算机输入其他值。

最底线是我永远都不知道需要存储什么类型。

4 个答案:

答案 0 :(得分:4)

已更新:根据评论和您的澄清:如果您事先不知道代码类型,则无法编写代码类型安全的代码。没有用。

因此,您必须继续使用反射或您自己的方式来注册类型元数据(包含有关其类型的一些有用信息的枚举或类)。

您可以使用上文所述的自己的元数据来构建UI,在特定情况下进行数据验证和所需的转换。


古老而又不太相关::如果您知道编译时的类型,则可以使用泛型使其看起来更加精简:

public T GetValueOrDefault<T>(string key)
{
    if (this.dictionary.TryGetValue(key, out object o))
    {
        return (T)(object)o;
    }

    return default(T);
}

可以肯定的是,您必须检查您的设计是否合理,但是我现在无法根据您的书面文字判断。

答案 1 :(得分:1)

您可以使用格式反序列化器(例如JSON / XML)读取输入并将其反序列化为给定的结构。

在您的情况下,您将定义一个类,其中包含您希望此输入文件提供的特定字段。 (此示例使用的是JSON,但是原理相同,无论符号格式如何)

public class Settings {

    public int Brightness { get; set; }

    public string Connection { get; set; }

}

然后您将像这样反序列化

var settings = JsonConvert.DeserializeObject<Settings>(fileInput)

解串器知道类型,因为您已经定义了它。 (请注意,不必为要创建的类型而存在每个字段。)

答案 2 :(得分:0)

  

但是有些东西告诉我这很丑,而且有更好的方法。

我完全同意您的假设。

似乎您实际上对实际类型有一些了解,但是只想在一个地方对这些信息进行反序列化即可。假设这种具有单个数据结构表示完全不相关的东西是一个坏主意,因为最终您会遇到一些奇怪的转换和类型检查解决方案的噩梦。特别是,您可以轻松编写在运行时失败的代码:

var a = (int)dict["Connection"];

相反,您应该具有表示这些信息的静态类型的数据类型。创建一个具有所有这些属性的类,并使用一些序列化程序库,例如Newtonsofts JSON.Net将这些属性反序列化为该数据结构。

class Settings
{
    public int Brightness { get; set; }
    public string Connection { get; set; }
}

现在,您可以轻松地反序列化您的设置:

var setting = JsonConvert.DeserializeObject<Settings>(myJson)

并且具有完全确定性的行为:

var b = setting.Brightness; // no casting to int neccessary

答案 3 :(得分:-1)

如果您在编译时不知道字典中的类型,可以使用dynamic标记(重做Patrick的示例):

public dynamic GetValueOrDefault(string key)
{
    if (this.dictionary.TryGetValue(key, out object o))
    {
        return o;
    }

    return null;
}

用例:

int val;

val = dict.GetValueOrDefault("Brightness");