C# “string”=“string”是否占用更多内存
作为我对这段代码进行重构的一部分,我遇到了这段代码,我正在讨论什么更正确/更有效 之前: 之后: 什么更好? 我考虑的是线型图案=图案[0]='*'?图案。子字符串1:pattern; 也就是说,从可读性的角度来看,我更喜欢第二种。但另一方面,此表达式的含义是以下两个选项: 模式[0]='*'->在这种情况下,模式将更改为pattern.Substring1 else->pattern=模式 如果我选择第一种方式,忽略命名等,我只有第一种选择:C# “string”=“string”是否占用更多内存,c#,.net,string,memory,C#,.net,String,Memory,作为我对这段代码进行重构的一部分,我遇到了这段代码,我正在讨论什么更正确/更有效 之前: 之后: 什么更好? 我考虑的是线型图案=图案[0]='*'?图案。子字符串1:pattern; 也就是说,从可读性的角度来看,我更喜欢第二种。但另一方面,此表达式的含义是以下两个选项: 模式[0]='*'->在这种情况下,模式将更改为pattern.Substring1 else->pattern=模式 如果我选择第一种方式,忽略命名等,我只有第一种选择: 底线:线条模式=模式需要更多内存吗?最好的方法可能
底线:线条模式=模式需要更多内存吗?最好的方法可能是
我更喜欢第一种方法,因为它更简单,并且使编译器更容易进行任何优化 老实说,我不知道编译器是否会在第二种方法中优化掉pattern=pattern。可能吧。只有速度测试才能帮助您确定这一点 就我个人而言,我觉得第二种方法更简洁,但可读性不强。如果我不需要这样做,我就不会编写为自身分配变量的代码
一个更可读的方法是使用String .Trimm,但是我认为效率不高。
< P>如果你允许从字符串的开头和结尾修剪所有**字符,比如**一些字符串**,那么你可以这样做:private string RemoveAllowedAstrisks(string pattern)
{
return pattern?.Trim('*');
}
我已经检查了生成的IL代码,看看创建了什么
IL_000e: ldloc.0 // hello
IL_000f: ldc.i4.0
IL_0010: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_0015: ldc.i4.s 42 // 0x2a
IL_0017: beq.s IL_001c
IL_0019: ldloc.0 // hello
IL_001a: br.s IL_0023
IL_001c: ldloc.0 // hello
IL_001d: ldc.i4.1
IL_001e: callvirt instance string [mscorlib]System.String::Substring(int32)
IL_0023: stloc.0 // hello
如您所见,如果逻辑语句的:分支运行IL0019,则会执行ldloc.0。紧接着,代码跳转到执行stloc.0的IL_0023
这可能是值类型的问题,但字符串是引用类型,这样的赋值根本不会影响内存。为了证明这一点,我创建了一个大字符串并运行了一些value=value赋值。堆大小从未改变
string hello = new string('a', 3202340);
hello = hello;
hello = hello;
下面如何:计算是从前面还是后面修剪一个字符,或者同时从前面或后面修剪两个字符,如果是,则返回一个子字符串,否则返回字符串本身
string CutHeadAndTail(string pattern)
{
var s = pattern[0] == '*' ? 1 : 0;
var e = pattern[pattern.Length - 1] == '*' ? 1 : 0;
return (s > 0 || e > 0) ?
pattern.Substring(s, pattern.Length - s - e) :
pattern;
}
它是1。正如汉斯指出的那样,这并不重要。2.string是一种引用类型,所以pattern=pattern完全不起作用。我不确定如何翻译成IL和机器码,如果这没有得到很好的优化,引用可能会从内存复制到cpu寄存器并再次复制到同一内存位置。请不要担心性能,但我想知道是否存在实际差异?@Roni检查差异的最简单方法是查看IL。使用LinqPad或类似工具最大的区别在于原始代码清晰易读。OP似乎担心内存使用,而不是速度。我猜Regex实例需要比当前解决方案更多的内存。使用Regex代替两个基本的字符串操作调用几乎总是大材小用。他询问内存和性能,询问更小的短语和编译,这太过分了。如果因为内存开销而考虑两次分配字符串,则正则表达式会执行一次一站式替换,即使它只创建了一次,也比当前解决方案中多了一次。不过,这稍微改变了原始方法的约定。RemoveAllowedStrisks**foo**将导致原始版本中的*foo*和此版本中的foo。这实际上应该是一个错误,绝对同意,但修剪选项不能作为解决方案,因为它破坏了以前的行为。@Roni:是的,它的逻辑不完全相同。例如,如果字符串以多个星号*开头,它将删除所有星号,而代码仅删除第一个星号。
using System.Text.RegularExpressions;
...
private static Regex leadingTrailingAsterisks = new Regex("(^\\*)|(\\*$)");
private static string RemoveAllowedAsterisks(string pattern)
{
return leadingTrailingAsterisks.Replace(pattern, "");
}
private string RemoveAllowedAstrisks(string pattern)
{
return pattern?.Trim('*');
}
IL_000e: ldloc.0 // hello
IL_000f: ldc.i4.0
IL_0010: callvirt instance char [mscorlib]System.String::get_Chars(int32)
IL_0015: ldc.i4.s 42 // 0x2a
IL_0017: beq.s IL_001c
IL_0019: ldloc.0 // hello
IL_001a: br.s IL_0023
IL_001c: ldloc.0 // hello
IL_001d: ldc.i4.1
IL_001e: callvirt instance string [mscorlib]System.String::Substring(int32)
IL_0023: stloc.0 // hello
string hello = new string('a', 3202340);
hello = hello;
hello = hello;
string CutHeadAndTail(string pattern)
{
var s = pattern[0] == '*' ? 1 : 0;
var e = pattern[pattern.Length - 1] == '*' ? 1 : 0;
return (s > 0 || e > 0) ?
pattern.Substring(s, pattern.Length - s - e) :
pattern;
}