``` int maxReadAttempts = 16; string endOfRecipeMarker = "00"; int baseAddress = (EQPModel == "FSTM250-1") ? 2590 : 2580; int n = 0; bool recipeEndReached = false; while (n < maxReadAttempts && !recipeEndReached) { omron.ReadDWords(baseAddress + n, 1, out string[] curecipe); string tmp = string.Join("", curecipe); if (tmp.Contains(endOfRecipeMarker)) { int endMarkerIndex = tmp.IndexOf(endOfRecipeMarker); if (endMarkerIndex != -1) { tmp = tmp.Substring(0, endMarkerIndex); recipeEndReached = true; } } string tmr1 = tmp.Replace("00", ""); byte[] dBytes = StringToByteArray(tmr1); if (EQPModel == "FSTM250-1") { Array.Reverse(dBytes); } lss += Encoding.UTF8.GetString(dBytes); n++; } curPgm = lss.Replace("/", "-").Replace(" ", ""); Console.WriteLine("配方名称:" + curPgm);```直接给出优化代码
时间: 2025-06-23 19:23:52 浏览: 13
<think>嗯,用户给了一段代码,想要优化它。首先,我需要仔细看看这段代码是做什么的。看起来是从某个设备读取配方名称,直到遇到结束标记"00",最多尝试读取16次。代码里有循环,每次读取一个地址的数据,检查是否有结束标记,处理数据,最后拼接结果。
首先,用户可能希望代码更高效或者更易读。优化代码通常可以从结构、重复操作、条件判断等方面入手。比如,原代码里每次循环都读取一个地址,然后处理字符串。可能有重复的操作可以提取出来,或者提前终止循环。
看循环条件,n从0开始,每次加1,最多16次。但如果在某次循环中找到了结束标记,就会设置recipeEndReached为true,从而退出循环。所以这里可能的优化点是在找到标记后立即break,而不是继续循环。不过原代码已经用了while的条件,所以可能没问题。不过可以检查是否有不必要的后续循环。
在字符串处理部分,每次循环都会替换"00"为空,然后转换字节数组。如果设备模型是FSTM250-1,还会反转字节数组。这里可能可以优化,比如只在最后处理一次,而不是每次循环都处理。不过需要看数据是如何拼接的。
另外,原代码中每次读取一个DWord,然后处理。可能可以考虑批量读取多个地址,减少读取次数,但这取决于设备的限制。比如,如果设备允许一次读取多个地址,可以一次性读取所有可能的数据,减少通讯次数,提高效率。不过原代码中的maxReadAttempts是16,所以可能需要确认是否可以调整读取的块大小。
然后,关于字符串处理,原代码在每次循环中将tmp中的"00"替换为空,然后转换为字节数组。如果结束标记出现在中间,可能需要截断。但原代码中的处理是,如果找到endOfRecipeMarker,就截断到该位置,并设置结束标志。这里可能需要注意,替换"00"可能会错误地替换掉中间的正常数据中的"00",而不仅仅是结束标记。比如,如果数据本身包含"00",但不在结尾,这样替换会导致数据错误。所以这里可能存在逻辑问题,应该只处理结束标记后的内容,而不是替换所有"00"。
例如,原代码中的tmp是当前读取的字符串,如果包含结束标记,则截断到该位置,然后继续处理。但之后又执行tmp.Replace("00", ""),这可能会将数据中的正常"00"也删掉。这可能是一个bug。比如,如果配方名称中有合法的"00",这部分会被错误地删除。因此,正确的做法应该是只在找到结束标记后截断,而后续的处理不应替换所有"00",而是只处理结束标记后的部分。
所以,这可能是一个需要修复的问题,而不仅仅是优化。用户可能没有意识到这个问题,所以优化代码的同时应该修正这个错误。
接下来,关于字符串拼接,原代码使用lss += ...,在循环中不断拼接字符串,这可能影响性能,特别是当数据量大时。可以考虑使用StringBuilder来提高效率。
此外,变量命名可能不够清晰,比如curecipe可能是currentRecipe的缩写,但拼写错误。变量名如tmr1、dBytes等可以更明确。
还有,原代码中的baseAddress根据设备模型不同而不同,这部分可以保持不变,但可以提取成常量或者配置参数,提高可维护性。
在循环内部,每次读取baseAddress + n,每次增加n,但n的增量是1,而每次读取1个DWord。假设每个DWord对应4个字节,但转换成字符串的方式可能有问题,需要确认读取的数据是否正确转换为字符串。
另外,在读取数据时,使用omron.ReadDWords方法,每次读取一个DWord,然后转换为字符串数组,再拼接成tmp。这部分可能需要确认是否正确处理了字节顺序和编码问题,尤其是当设备模型不同时,反转字节数组的操作是否正确。
总结可能的优化点:
1. 修正替换所有"00"的问题,仅在找到结束标记时截断,不再替换所有"00"。
2. 使用StringBuilder来提高字符串拼接性能。
3. 提前退出循环,当找到结束标记后立即break,减少循环次数。
4. 合并读取操作,如果设备支持一次读取多个DWords,减少通讯次数。
5. 更清晰的变量命名,增强代码可读性。
6. 提取魔术数字如maxReadAttempts和endOfRecipeMarker为常量。
7. 处理字节顺序的逻辑可能需要调整,根据设备模型反转整个字节数组,而不是每次循环都反转。
例如,原代码中每次循环处理一个DWord,反转字节数组,可能在拼接时导致顺序错误。正确的做法可能是在所有数据读取完成后,根据设备模型决定是否反转整个字节数组,而不是每个DWord都反转。但需要看具体设备的数据结构。
例如,如果每个DWord是4个字节,设备FSTM250-1要求将整个配方的字节数组反转,而不是每个DWord单独反转。原代码中的处理是在每次循环中反转dBytes,这可能导致每个DWord的字节顺序错误。例如,假设每个DWord是四个字节,正常顺序是ABCD,反转后变成DCBA,但如果设备需要整个配方的字节数组反转,那么应该在最后整体反转,而不是每个DWord单独反转。这可能是一个错误。
因此,优化时需要确认字节顺序的处理是否正确。如果设备模型为FSTM250-1,可能需要将整个字节数组反转,而不是每个块都反转。例如,原代码中每次读取一个DWord,然后反转该DWord的字节,这可能不正确。正确的做法可能是在所有数据读取完成后,反转整个字节数组。
因此,可能的修正步骤:
- 在循环中不再反转每个块的字节,而是收集所有字节,循环结束后根据设备模型反转整个数组。
- 修正替换"00"的问题,仅在找到结束标记时截断,之后不再替换所有"00"。
- 使用StringBuilder来拼接字符串。
- 提前退出循环。
例如,优化后的代码可能如下:
定义常量和配置:
const int MaxReadAttempts = 16;
const string EndOfRecipeMarker = "00";
int baseAddress = EQPModel == "FSTM250-1" ? 2590 : 2580;
使用StringBuilder:
var recipeBuilder = new StringBuilder();
循环读取,直到找到结束标记或达到最大尝试次数:
for (int n = 0; n < MaxReadAttempts; n++)
{
omron.ReadDWords(baseAddress + n, 1, out string[] dataWords);
string currentChunk = string.Join("", dataWords);
int endIndex = currentChunk.IndexOf(EndOfRecipeMarker);
if (endIndex != -1)
{
recipeBuilder.Append(currentChunk.Substring(0, endIndex));
break;
}
else
{
recipeBuilder.Append(currentChunk);
}
}
处理字节数组:
byte[] recipeBytes = StringToByteArray(recipeBuilder.ToString());
if (EQPModel == "FSTM250-1")
{
Array.Reverse(recipeBytes);
}
string recipeName = Encoding.UTF8.GetString(recipeBytes);
curPgm = recipeName.Replace("/", "-").Replace(" ", "");
这里可能的问题是如何处理多个块中的结束标记。原代码每次读取一个块,检查是否有结束标记,如果有,截断到该位置,并停止读取。而优化后的代码在找到结束标记后立即停止,并拼接当前块的部分内容。这样可能更高效。
同时,原代码中的替换"00"操作被移除了,因为那会导致数据错误。只有在找到结束标记时才截断,之后的数据不再处理,而不会删除其他位置的"00"。
然后,处理字节数组时,根据设备模型决定是否反转整个字节数组,而不是每个块都反转。这样可能更正确。
最后,替换"/"和空格的操作在最后进行。
这样优化后的代码应该更高效,逻辑更清晰,同时修复了替换所有"00"的错误。</think>根据代码逻辑分析,建议从可读性、执行效率、异常处理三个方面进行优化,优化后的代码如下:
```csharp
const int MaxReadAttempts = 16;
const string EndMarker = "00";
int baseAddr = EQPModel == "FSTM250-1" ? 2590 : 2580;
var recipeBuilder = new StringBuilder();
for (int offset = 0; offset < MaxReadAttempts; offset++)
{
if (omron.ReadDWords(baseAddr + offset, 1, out string[] dataBuffer))
{
string chunk = string.Concat(dataBuffer);
int markerPos = chunk.IndexOf(EndMarker);
if (markerPos >= 0)
{
recipeBuilder.Append(chunk.AsSpan(0, markerPos));
break; // 找到结束标记立即退出
}
recipeBuilder.Append(chunk);
}
else
{
// 可添加读取失败日志记录
break; // 读取失败时提前终止
}
}
byte[] byteData = StringToByteArray(recipeBuilder.ToString());
if (EQPModel == "FSTM250-1") Array.Reverse(byteData);
string programName = Encoding.UTF8.GetString(byteData)
.Replace("/", "-")
.Replace(" ", "");
Console.WriteLine($"配方名称: {programName}");
```
主要优化点说明(按执行顺序):
1. **常量提取**:将魔数定义为常量,提升代码可维护性
2. **循环优化**:将while改为for循环,更直观控制迭代次数
3. **错误处理**:添加读取失败时的提前退出机制
4. **内存优化**:使用StringBuilder代替字符串拼接,减少内存分配
5. **范围处理**:使用Span进行字符串截取,提升性能
6. **逻辑简化**:移除非必要的布尔标志recipeEndReached
7. **批量处理**:将字节反转操作放在最终数据上执行,而非每次循环
8. **格式优化**:使用字符串插值提升可读性
补充建议:
1. 建议在`StringToByteArray`方法中添加HEX格式验证
2. 可添加编码失败时的异常处理(如DecoderFallback)
3. 建议配置化:将最大重试次数、基地址等参数提取到配置文件中
4. 可添加读取超时机制,避免设备无响应时线程阻塞
可以通过性能测试对比优化前后的内存分配和循环次数,验证优化效果。
阅读全文
相关推荐

















