说我有一堂课:
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) },
将变得更加整洁。在这种情况下,我可以做些对属性有用的事情(避免反射)吗?
此外,我是否完全错了?有没有一种方法可以使它旋转,从而使字符串和属性之间的连接真正简洁明了?目前,我似乎经常需要合理地将字符串与类似的属性相关联(或传递指向属性本身的指针),并且任何建议都将不胜感激。
答案 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