将字符串与C#中的属性相关

时间:2019-07-18 16:24:33

标签: c# properties

说我有一堂课:

class Thing
{
    public string Id { get; set; }
    public string Foo { get; set; }
    public string Bar { get; set; }
}

我有一种URL参数样式约定,在这里我希望允许使用以下字符串格式指定此类的值:

"{Id}~foo={foo}~bar={bar}"

我可能想编写一个类似这样的类:

class ThingHandler
{
    private static readonly IDictionary<string, (Func<Thing, string> GetValue, Action<Thing, string> SetValue)> dictionary =
        new Dictionary<string, (Func<Thing, string> GetValue, Action<Thing, string> SetValue)>
        {
            { "foo=", (new Func<Thing, string>((thing) => thing.Foo), new Action<Thing, string>((thing, value) => thing.Foo = value)) },
            { "bar=", (new Func<Thing, string>((thing) => thing.Bar), new Action<Thing, string>((thing, value) => thing.Bar = value)) },
        };

    public Thing Unstringify(string str)
    {
        Thing thing = new Thing();

        var split = str.Split('~');

        thing.Id = split.First();

        foreach (var keyValuePair in split.Skip(1))
        {
            var key = keyValuePair.Substring(0, 4);
            var value = keyValuePair.Substring(4);
            dictionary[key].SetValue(thing, value);
        }

        return thing;
    }

    public string Stringify(Thing thing)
    {
        StringBuilder stringBuilder = new StringBuilder(thing.Id);

        foreach (var item in dictionary)
        {
            var value = item.Value.GetValue(thing);
            if (!string.IsNullOrEmpty(value))
            {
                stringBuilder.Append(item.Key);
                stringBuilder.Append(value);
            }
        }

        return stringBuilder.ToString();
    }
}

用这样两种不同的方式指定属性似乎非常不明智,并且最终在这两个字典条目中出现了很多重复的代码。可以使用反射来减轻混乱的可能性吗?但是,再次,这感觉不应该是我的。像这样:

{ "foo=", Property<Thing>((thing) => thing.Foo) },
{ "bar=", Property<Thing>((thing) => thing.Bar) },

将变得更加整洁。在这种情况下,我可以做些对属性有用的事情(避免反射)吗?

此外,我是否完全错了?有没有一种方法可以使它旋转,从而使字符串和属性之间的连接真正简洁明了?目前,我似乎经常需要合理地将字符串与类似的属性相关联(或传递指向属性本身的指针),并且任何建议都将不胜感激。

3 个答案:

答案 0 :(得分:1)

此问题是OP试图在此处澄清其原始问题的尝试: Is there a way to store a pointer to a property in C#?

OP最初表示,他经常需要这样做,这表明他可能不正确地解决了该问题。看看上面他的新问题,似乎是一个序列化问题。

OP应该阅读有关序列化的所有内容,然后查看他是否可以提出现成的解决方案。其他响应者建议使用Newtonsoft JSON,我也认为这可能是OP的合适解决方案。众所周知,Newtonsoft的速度非常快,这使得它几乎可以在任何情况下运行。它也很健壮。

我建议不使用Json序列化的唯一原因是,OP是否需要他自己更易于理解的格式。即使这是他的需要,还是有一些现成的方法来实现这一目标。再次,OP在继续之前应阅读有关序列化的所有内容。

答案 1 :(得分:0)

对于仅一种Thing类型,一种模式是让stringify方法成为原始类的成员:

class Thing
{
    public string Id { get; set; }
    public string Foo { get; set; }
    public string Bar { get; set; }

    public static Thing FromString(string input)
    {
        var result = new Thing();
        var split = input.Split('~');

        result.Id = split[0];

        foreach (var keyValuePair in split.Skip(1))
        {
            var key = keyValuePair.Substring(0, 3).ToLower();

            if (key == "foo")
                result.Foo = keyValuePair.Substring(4);
            if (key == "bar")
                result.Bar = keyValuePair.Substring(4); 
        }

        return result;
    }

    public overrides string ToString()
    {
        return $"{Id}~foo={Foo}~bar={Bar}";
    }
}

选择覆盖ToString()方法可能特别好,但是如果您需要处理多个静态 Builder Factory 类,也可以改用配对的静态 Builder Factory 类。不同的格式,其中方法或类型名称可以指示上下文。

但是,使用字典似乎是尝试使具有未知或各种属性的任何随机类型(或几种特定类型)都可以使用此字典。在这种情况下,如果您想要更多可重复的通用实现,则可能需要阅读serialization的更多信息。该链接仅适用于.Net中的内置内容。您还可以使用许多其他库来处理这种事情。

答案 2 :(得分:0)

关于代码的用途,正如其他人所说,我宁愿使用标准JSON序列化,例如使用Newtonsoft JSON。

关于问题的属性部分,不可能简单地定义一个指向属性的指针以避免代码重复。

不过有一件事:您可以在诸如这样的属性上使用nameof()

class X
{
    bool Y {get;set;}
    void string foo() => nameof(Y);
}

new X().foo(); // return "Y"

在另一个stackoverflow问题中,我提出了一种创建属性指针的方法,但这更多是概念的证明,而非真正可用的东西:PropertyPointer