C# 重构大开关案例以设置属性
大家好,这是我的第一个问题我希望它是好的\o/ 因此,首先是c#应用程序通过套接字不断接收数据,当我第一次连接到服务器并发出请求时,我会收到这个大字符串(包含100多个字段),为了便于示例,我会将其缩小:C# 重构大开关案例以设置属性,c#,switch-statement,refactoring,C#,Switch Statement,Refactoring,大家好,这是我的第一个问题我希望它是好的\o/ 因此,首先是c#应用程序通过套接字不断接收数据,当我第一次连接到服务器并发出请求时,我会收到这个大字符串(包含100多个字段),为了便于示例,我会将其缩小: 0:7:1:Augusto:2:Question:3:Stackoverflow:4:Question:5:201609262219:6:stuff:7:stuff:..:100:! 在收到这个大字符串之后,我只会收到更新,例如: 0:7:3:Changed Topic:4:Doubt:5:
0:7:1:Augusto:2:Question:3:Stackoverflow:4:Question:5:201609262219:6:stuff:7:stuff:..:100:!
在收到这个大字符串之后,我只会收到更新,例如:
0:7:3:Changed Topic:4:Doubt:5:2016092710:100:!
字段100将始终出现,因为它定义了字符串终止符。当我收到这个大字符串时,我必须构建一个对象问题,这个大字符串将始终产生一个问题对象,因此我们有:
public class Question
{
public string Id { get; set; }
public string Name { get; set; }
public string Action { get; set; }
public string Topic { get; set; }
public string Body { get; set; }
public string Time { get; set; }
...
public string 99 { get; set; }
}
要构建问题对象,我执行了以下操作:
public void Process(string data)
{
Question question = new Question();
String[] fields = data.split(“:”);
for(int i = 0; i < fields.Length; i +=2) {
Switch (fields[i]) {
case "0":
question.Id = fields[i+1]
break;
case "1":
question.Name = fields[i+1]
break;
case "2":
question.Action = fields[i+1]
break;
case "3":
question.Topic = fields[i+1]
break;
case "4":
question.Body = fields[i+1]
break;
case "5":
question.Time = fields[i+1]
break;
...
case "99":
Question.99 = fields[i+1]
break;
}
}
}
公共作废处理(字符串数据)
{
问题=新问题();
String[]fields=data.split(“:”);
对于(int i=0;i
我研究了stackoverflow的答案,但它们与我试图实现的不同。我认为使用策略模式或命令模式是不值得的,因为逻辑很简单,使用这种模式会增加太多的复杂性。
我不确定一本
字典是否能解决我的问题,我想这和巫婆案是一样的。
我也考虑过使用反射(setValue),但我认为它会很慢,我真的需要这个东西来飞行
这里的问题是,我只是将一个值赋给对象,我不想做这个大的转换。我认为我创建对象的方式有些错误,但我无法找到不同的解决方案
还有一个问题,你们认为string.Split()
会成为我代码的瓶颈吗?因为我调用这个方法需要很多时间,比如每秒100次
谢谢
---更新
修复了示例和案例“5”。您可以像这样重构代码:
public void Process(string data)
{
var assignments = new Dictionary<string, Action<Question, string>>()
{
{ "0", (q, t) => q.Id = t },
{ "1", (q, t) => q.Name = t },
// ...
{ "99", (q, t) => q._99 = t },
};
Question question = new Question();
string[] fields = data.Split(':');
for (int i = 0; i < fields.Length; i += 2)
{
assignments[fields[i]](question, fields[i + 1]);
}
}
我认为您担心这种情况下的过早优化。一般的经验法则是——除非性能问题实际上是可测量的,否则不要进行优化
考虑到这一点,这个问题可以在一个相当优雅的庄园里解决。我将使用一点缓存反射,以便只提取一次PropertyInfo
及其自定义属性。因此,您将看到在初始连接上有少量的性能开销。在这一点上,这是非常快的
因为我调用这个方法需要很多时间,比如每秒100次
我在一台Windows10虚拟机上运行了它,该虚拟机有4个内核和8gb的ram。我运行了一个测试,在一个包含100个值的字符串上进行了10000次迭代(没有使用缩短的字符串),我看到每个字符串的平均解析时间为516.32次(每1ms 10000次)。考虑到您的需求是1秒内100个字符串,这对于您的吞吐量来说应该足够快。我能够在1秒的时间内解析20000多个。每秒解析的数量最终将高于20000 I进程,因为我每次都要消耗整个100个元素的字符串,而不是较小的更新字符串
长期运行可能会有一些GC压力,我必须运行测试才能看到。这可以通过引入两个对象池来优化,以减少分配。无论采用何种方法,都会出现此问题,因为您必须将一个字符串解析为多个值,所以此解决方案不会试图解决此问题
让我们从我的字符串开始,它包含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:!
然后,我创建了一个属性
,可用于将元素映射到模型属性
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;
});
Dictionary properties=typeof(Question).GetProperties().ToDictionary(
property=>property.GetCustomAttribute()字段,
属性=>
{
var attribute=property.GetCustomAttribute();
属性。属性=属性;
返回属性;
});
在应用程序的生命周期中只执行一次。您将在从服务器得到的每个响应中重复使用该字典。现在,当您从服务器接收到更新时,只需使用属性解析它
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]);
}
}
void解析(字符串消息、字典字段映射)
{
字符串[]messageContent=message.Split(“:”);
变量问题=新问题();
for(int index=0;index
这里没有什么特别的东西。
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]);
}
}