C# 返回新类型和返回对象之间有区别吗?

C# 返回新类型和返回对象之间有区别吗?,c#,coding-style,C#,Coding Style,在C#中,为两种不同的书写方式生成的字节码是否有任何差异,我希望是相同的: 返回创建的对象: public MemoryStream GetStream() { MemoryStream s = new MemoryStream(this.GetBytes()); return s; } 返回新的: public MemoryStream GetStream() { return new MemoryStream(this.GetBytes()); } 是否会优化任何差异?还是第

在C#中,为两种不同的书写方式生成的字节码是否有任何差异,我希望是相同的:

返回创建的对象:

public MemoryStream GetStream() {
  MemoryStream s = new MemoryStream(this.GetBytes());
  return s;
}
返回新的:

public MemoryStream GetStream() {
  return new MemoryStream(this.GetBytes());
}

是否会优化任何差异?还是第一个比第二个更容易被垃圾收集?或者这只是个人喜好?

看看IL代码,第二个版本中的步骤似乎比第一个版本少

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream1 () cil managed 
{
    // Method begins at RVA 0x22c0
    // Code size 13 (0xd)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s,
        [1] class [mscorlib]System.IO.MemoryStream CS$1$0000
    )

    IL_0000: nop
    IL_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: stloc.1
    IL_0009: br.s IL_000b

    IL_000b: ldloc.1
    IL_000c: ret
} // end of method Form1::GetStream1

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream2 () cil managed 
{
    // Method begins at RVA 0x22dc
    // Code size 11 (0xb)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream CS$1$0000
    )

    IL_0000: nop
    IL_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0006: stloc.0
    IL_0007: br.s IL_0009

    IL_0009: ldloc.0
    IL_000a: ret
} // end of method Form1::GetStream2
它似乎并没有做更多的事情,但还是多走了几步

@Alexei Levenkov,这是代码的发布版本

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream1 () cil managed 
{
    // Method begins at RVA 0x2264
    // Code size 8 (0x8)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s
    )

    IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0005: stloc.0
    IL_0006: ldloc.0
    IL_0007: ret
} // end of method Form1::GetStream1

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream2 () cil managed 
{
    // Method begins at RVA 0x2278
    // Code size 6 (0x6)
    .maxstack 8

    IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0005: ret
} // end of method Form1::GetStream2

看起来还是稍微多一点。

看看IL代码,第二个版本中的步骤似乎比第一个版本少

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream1 () cil managed 
{
    // Method begins at RVA 0x22c0
    // Code size 13 (0xd)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s,
        [1] class [mscorlib]System.IO.MemoryStream CS$1$0000
    )

    IL_0000: nop
    IL_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0006: stloc.0
    IL_0007: ldloc.0
    IL_0008: stloc.1
    IL_0009: br.s IL_000b

    IL_000b: ldloc.1
    IL_000c: ret
} // end of method Form1::GetStream1

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream2 () cil managed 
{
    // Method begins at RVA 0x22dc
    // Code size 11 (0xb)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream CS$1$0000
    )

    IL_0000: nop
    IL_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0006: stloc.0
    IL_0007: br.s IL_0009

    IL_0009: ldloc.0
    IL_000a: ret
} // end of method Form1::GetStream2
它似乎并没有做更多的事情,但还是多走了几步

@Alexei Levenkov,这是代码的发布版本

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream1 () cil managed 
{
    // Method begins at RVA 0x2264
    // Code size 8 (0x8)
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s
    )

    IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0005: stloc.0
    IL_0006: ldloc.0
    IL_0007: ret
} // end of method Form1::GetStream1

.method public hidebysig 
    instance class [mscorlib]System.IO.MemoryStream GetStream2 () cil managed 
{
    // Method begins at RVA 0x2278
    // Code size 6 (0x6)
    .maxstack 8

    IL_0000: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor()
    IL_0005: ret
} // end of method Form1::GetStream2

这两个代码片段基本相同,但性能差异很小,可以忽略不计。从它们中选择代码样式和方法功能是一个问题。 如果您的方法除了返回
MemoryStream
对象之外不应该执行任何其他操作,那么第二个代码片段就足够了,但是如果您需要在返回
MemoryStream
对象之前对其执行一些操作,则必须使用第一个。
垃圾收集方面没有区别。

这两个代码段基本相同,性能差异很小,可以忽略不计,从中选择代码样式和方法功能是一个问题。 如果您的方法除了返回
MemoryStream
对象之外不应该执行任何其他操作,那么第二个代码片段就足够了,但是如果您需要在返回
MemoryStream
对象之前对其执行一些操作,则必须使用第一个。
垃圾收集方面没有区别。

如果使用Reflector检查为此生成的代码:

public MemoryStream GetStream(byte[] bytes)
{
    MemoryStream s = new MemoryStream(bytes);
    return s;
}
对于发布版本,您可以获得以下信息:

.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s)
    L_0000: ldarg.1 
    L_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ret 
}
.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s,
        [1] class [mscorlib]System.IO.MemoryStream CS$1$0000)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: stloc.1 
    L_000a: br L_000f
    L_000f: ldloc.1 
    L_0010: ret 
}
如您所见,C#编译器优化了额外的变量

但是,对于调试生成,您会得到以下结果:

.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s)
    L_0000: ldarg.1 
    L_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ret 
}
.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s,
        [1] class [mscorlib]System.IO.MemoryStream CS$1$0000)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: stloc.1 
    L_000a: br L_000f
    L_000f: ldloc.1 
    L_0010: ret 
}
显然,编译器无法优化掉调试构建的额外变量,以防您想在调试时检查它


因此,如果您想保留额外的变量以进行调试,那么这没关系-它对发布版本没有影响。

如果您使用Reflector检查为此生成的代码:

public MemoryStream GetStream(byte[] bytes)
{
    MemoryStream s = new MemoryStream(bytes);
    return s;
}
对于发布版本,您可以获得以下信息:

.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s)
    L_0000: ldarg.1 
    L_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ret 
}
.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s,
        [1] class [mscorlib]System.IO.MemoryStream CS$1$0000)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: stloc.1 
    L_000a: br L_000f
    L_000f: ldloc.1 
    L_0010: ret 
}
如您所见,C#编译器优化了额外的变量

但是,对于调试生成,您会得到以下结果:

.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s)
    L_0000: ldarg.1 
    L_0001: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0006: stloc.0 
    L_0007: ldloc.0 
    L_0008: ret 
}
.method public hidebysig instance class [mscorlib]System.IO.MemoryStream GetStream(uint8[] bytes) cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.IO.MemoryStream s,
        [1] class [mscorlib]System.IO.MemoryStream CS$1$0000)
    L_0000: nop 
    L_0001: ldarg.1 
    L_0002: newobj instance void [mscorlib]System.IO.MemoryStream::.ctor(uint8[])
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: stloc.1 
    L_000a: br L_000f
    L_000f: ldloc.1 
    L_0010: ret 
}
显然,编译器无法优化掉调试构建的额外变量,以防您想在调试时检查它


因此,如果您想保留额外的变量以进行调试,那么这没关系——它对发布版本没有影响。

我相信优化后的JITed代码是相同的

这肯定不会对GC行为产生影响,因为对象的生存期将由使用返回值的人决定(您可能会考虑在函数结束之前不再使用值的情况,这显然不是这里的情况-
s
在方法执行结束时返回)


在非优化(调试)构建中唯一值得注意的区别是,您可以看到
s
变量的值

我相信优化后的JITed代码是相同的

这肯定不会对GC行为产生影响,因为对象的生存期将由使用返回值的人决定(您可能会考虑在函数结束之前不再使用值的情况,这显然不是这里的情况-
s
在方法执行结束时返回)


在非优化(调试)构建中唯一值得注意的区别是,您可以看到
s
变量的值

我想,这是个人喜好。我看不出这段代码可以做什么优化。无论如何,编译器都会内联整个方法。我想,这是个人的偏好。我看不出可以对此代码进行什么优化。编译器仍将内联整个方法。您确定它不是非优化IL(来自调试生成)?您确定它不是非优化IL(来自调试生成)?但是,当您调用GetStream时,优化器是否会在发布版本中内联它,这样看起来该方法甚至不存在。至少在使用此类帮助器方法查找堆栈跟踪程序时经常会发生这种情况。@JanneMatikainen JIT编译器可能会这样做,但C#编译器当然不会这样做。但是,当您调用GetStream时,优化器不会在发布版本中将其内联,这样看起来该方法甚至不存在。至少在使用此类助手方法查找堆栈跟踪程序时,这种情况经常发生。@JanneMatikainen JIT编译器可能会这样做,但C#编译器当然不会这样做。