我认为您担心在这种情况下过早优化。一般的经验法则是 - 除非性能问题实际上是可衡量的,否则不要优化。
考虑到这一点,这个问题可以在一个相当优雅的庄园中解决。我将使用一点 cached 反射,以便我只提取一次 PropertyInfo 及其自定义属性。因此,您会在初始连接上看到很小的性能开销。在这一点上,这是非常快的。
因为我多次调用 Process(data) 方法,比如每秒 100 次。
我在具有 4 个内核和 8GB 内存的 Windows 10 虚拟机中运行此程序。我对包含 100 个值的字符串进行了 10,000 次迭代(没有使用缩短的字符串),我看到每个字符串的平均解析时间为 516.32 ticks(每 1ms 10,000 个滴答声)。考虑到您的要求是 1 秒内 100 个字符串,这对于您的吞吐量应该足够快。我能够在 1 秒的时间范围内解析超过 20,000 个。每秒解析的次数最终将高于我处理的 20,000 次,因为我每次都使用整个 100 个元素字符串而不是较小的更新字符串。
长期运行可能会有一些 GC 压力,我必须运行测试才能看到。这可以通过引入几个对象池来减少分配来优化。无论您采用哪种方法,您都会遇到此问题,仅仅是因为您必须将 1 个字符串解析为多个值,因此此解决方案不会尝试解决此问题。
让我们从包含 100 个元素的字符串开始。
0:FizBam Foo Bar:1:FizBam Foo Bar:2:FizBam Foo Bar:3:FizBam Foo Bar:4:FizBam Foo Bar:5:FizBam Foo Bar:6:FizBam Foo Bar:7:FizBam Foo Bar:8:FizBam Foo Bar:9:FizBam Foo Bar:10:FizBam Foo Bar:11:FizBam Foo Bar:12:FizBam Foo Bar:13:FizBam Foo Bar:14:FizBam Foo Bar:15:FizBam Foo Bar:16:FizBam Foo Bar:17:FizBam Foo Bar:18:FizBam Foo Bar:19:FizBam Foo Bar:20:FizBam Foo Bar:21:FizBam Foo Bar:22:FizBam Foo Bar:23:FizBam Foo Bar:24:FizBam Foo Bar:25:FizBam Foo Bar:26:FizBam Foo Bar:27:FizBam Foo Bar:28:FizBam Foo Bar:29:FizBam Foo Bar:30:FizBam Foo Bar:31:FizBam Foo Bar:32:FizBam Foo Bar:33:FizBam Foo Bar:34:FizBam Foo Bar:35:FizBam Foo Bar:36:FizBam Foo Bar:37:FizBam Foo Bar:38:FizBam Foo Bar:39:FizBam Foo Bar:40:FizBam Foo Bar:41:FizBam Foo Bar:42:FizBam Foo Bar:43:FizBam Foo Bar:44:FizBam Foo Bar:45:FizBam Foo Bar:46:FizBam Foo Bar:47:FizBam Foo Bar:48:FizBam Foo Bar:49:FizBam Foo Bar:50:FizBam Foo Bar:51:FizBam Foo Bar:52:FizBam Foo Bar:53:FizBam Foo Bar:54:FizBam Foo Bar:55:FizBam Foo Bar:56:FizBam Foo Bar:57:FizBam Foo Bar:58:FizBam Foo Bar:59:FizBam Foo Bar:60:FizBam Foo Bar:61:FizBam Foo Bar:62:FizBam Foo Bar:63:FizBam Foo Bar:64:FizBam Foo Bar:65:FizBam Foo Bar:66:FizBam Foo Bar:67:FizBam Foo Bar:68:FizBam Foo Bar:69:FizBam Foo Bar:70:FizBam Foo Bar:71:FizBam Foo Bar:72:FizBam Foo Bar:73:FizBam Foo Bar:74:FizBam Foo Bar:75:FizBam Foo Bar:76:FizBam Foo Bar:77:FizBam Foo Bar:78:FizBam Foo Bar:79:FizBam Foo Bar:80:FizBam Foo Bar:81:FizBam Foo Bar:82:FizBam Foo Bar:83:FizBam Foo Bar:84:FizBam Foo Bar:85:FizBam Foo Bar:86:FizBam Foo Bar:87:FizBam Foo Bar:88:FizBam Foo Bar:89:FizBam Foo Bar:90:FizBam Foo Bar:91:FizBam Foo Bar:92:FizBam Foo Bar:93:FizBam Foo Bar:94:FizBam Foo Bar:95:FizBam Foo Bar:96:FizBam Foo Bar:97:FizBam Foo Bar:98:FizBam Foo Bar:99:FizBam Foo Bar:100:!
然后我创建了一个Attribute,我可以使用它来将元素映射到模型属性。
public class MapAttribute : Attribute
{
public MapAttribute(string fieldKey)
{
this.Field = fieldKey;
}
public string Field { get; private set; }
public PropertyInfo Property { get; set; }
public void SetValue(Question question, string value)
{
this.Property.SetValue(question, value);
}
}
现在,在您的模型上,您只需将属性映射到传入字段即可。当一个字段进入时,您将它与问题的实例一起传递给属性并让它分配值。您也可以在某种查找表中处理此问题,但属性似乎是允许您向模型添加新属性并在单个位置更新映射的最简单方法。
我在这里展示了整个模型,其中有 100 个属性映射到服务器响应。
public class Question
{
[Map("0")]
public string FooBar { get; set; }
[Map("1")]
public string Id { get; set; }
[Map("2")]
public string Action { get; set; }
[Map("3")]
public string Topic { get; set; }
[Map("4")]
public string Body { get; set; }
[Map("5")]
public string Time { get; set; }
[Map("6")]
public string Query { get; set; }
[Map("7")]
public string Answer { get; set; }
[Map("8")]
public string __8 { get; set; }
[Map("9")]
public string __9 { get; set; }
[Map("10")]
public string __10 { get; set; }
[Map("11")]
public string __11 { get; set; }
[Map("12")]
public string __12 { get; set; }
[Map("13")]
public string __13 { get; set; }
[Map("14")]
public string __14 { get; set; }
[Map("15")]
public string __15 { get; set; }
[Map("16")]
public string __16 { get; set; }
[Map("17")]
public string __17 { get; set; }
[Map("18")]
public string __18 { get; set; }
[Map("19")]
public string __19 { get; set; }
[Map("20")]
public string __20 { get; set; }
[Map("21")]
public string __21 { get; set; }
[Map("22")]
public string __22 { get; set; }
[Map("23")]
public string __23 { get; set; }
[Map("24")]
public string __24 { get; set; }
[Map("25")]
public string __25 { get; set; }
[Map("26")]
public string __26 { get; set; }
[Map("27")]
public string __27 { get; set; }
[Map("28")]
public string __28 { get; set; }
[Map("29")]
public string __29 { get; set; }
[Map("30")]
public string __30 { get; set; }
[Map("31")]
public string __31 { get; set; }
[Map("32")]
public string __32 { get; set; }
[Map("33")]
public string __33 { get; set; }
[Map("34")]
public string __34 { get; set; }
[Map("35")]
public string __35 { get; set; }
[Map("36")]
public string __36 { get; set; }
[Map("37")]
public string __37 { get; set; }
[Map("38")]
public string __38 { get; set; }
[Map("39")]
public string __39 { get; set; }
[Map("40")]
public string __40 { get; set; }
[Map("41")]
public string __41 { get; set; }
[Map("42")]
public string __42 { get; set; }
[Map("43")]
public string __43 { get; set; }
[Map("44")]
public string __44 { get; set; }
[Map("45")]
public string __45 { get; set; }
[Map("46")]
public string __46 { get; set; }
[Map("47")]
public string __47 { get; set; }
[Map("48")]
public string __48 { get; set; }
[Map("49")]
public string __49 { get; set; }
[Map("50")]
public string __50 { get; set; }
[Map("51")]
public string __51 { get; set; }
[Map("52")]
public string __52 { get; set; }
[Map("53")]
public string __53 { get; set; }
[Map("54")]
public string __54 { get; set; }
[Map("55")]
public string __55 { get; set; }
[Map("56")]
public string __56 { get; set; }
[Map("57")]
public string __57 { get; set; }
[Map("58")]
public string __58 { get; set; }
[Map("59")]
public string __59 { get; set; }
[Map("60")]
public string __60 { get; set; }
[Map("61")]
public string __61 { get; set; }
[Map("62")]
public string __62 { get; set; }
[Map("63")]
public string __63 { get; set; }
[Map("64")]
public string __64 { get; set; }
[Map("65")]
public string __65 { get; set; }
[Map("66")]
public string __66 { get; set; }
[Map("67")]
public string __67 { get; set; }
[Map("68")]
public string __68 { get; set; }
[Map("69")]
public string __69 { get; set; }
[Map("70")]
public string __70 { get; set; }
[Map("71")]
public string __71 { get; set; }
[Map("72")]
public string __72 { get; set; }
[Map("73")]
public string __73 { get; set; }
[Map("74")]
public string __74 { get; set; }
[Map("75")]
public string __75 { get; set; }
[Map("76")]
public string __76 { get; set; }
[Map("77")]
public string __77 { get; set; }
[Map("78")]
public string __78 { get; set; }
[Map("79")]
public string __79 { get; set; }
[Map("80")]
public string __80 { get; set; }
[Map("81")]
public string __81 { get; set; }
[Map("82")]
public string __82 { get; set; }
[Map("83")]
public string __83 { get; set; }
[Map("84")]
public string __84 { get; set; }
[Map("85")]
public string __85 { get; set; }
[Map("86")]
public string __86 { get; set; }
[Map("87")]
public string __87 { get; set; }
[Map("88")]
public string __88 { get; set; }
[Map("89")]
public string __89 { get; set; }
[Map("90")]
public string __90 { get; set; }
[Map("91")]
public string __91 { get; set; }
[Map("92")]
public string __92 { get; set; }
[Map("93")]
public string __93 { get; set; }
[Map("94")]
public string __94 { get; set; }
[Map("95")]
public string __95 { get; set; }
[Map("96")]
public string __96 { get; set; }
[Map("97")]
public string __97 { get; set; }
[Map("98")]
public string __98 { get; set; }
[Map("99")]
public string __99 { get; set; }
[Map("100")]
public string __100 { get; set; }
}
现在,当建立第一个连接时,获取所有属性及其属性并将它们缓存在字典中。
Dictionary<string, MapAttribute> properties = typeof(Question).GetProperties().ToDictionary(
property => property.GetCustomAttribute<MapAttribute>().Field,
property =>
{
var attribute = property.GetCustomAttribute<MapAttribute>();
attribute.Property = property;
return attribute;
});
在应用的生命周期内只执行一次。您将在从服务器获得的每个响应中重复使用该字典。现在,当您收到来自服务器的更新时,您只需使用属性对其进行解析。
void Parse(string message, Dictionary<string, MapAttribute> fieldMapping)
{
string[] messageContent = message.Split(':');
var question = new Question();
for (int index = 0; index < messageContent.Length; index++)
{
string field = messageContent[index];
MapAttribute mapping = fieldMapping[field];
index++;
mapping.SetValue(question, messageContent[index]);
}
}
这里没有什么花哨的东西。我们刚刚将您的 switch 语句替换为字典查找和用于处理将响应键映射到模型属性的属性。极大地减少了您必须编写的最终代码,并让您将来只需使用新属性更新您的模型。简单且易于维护。您可以通过不太担心性能来实现这一点,直到性能真正成为一个可衡量的问题。