c#中私有静态方法有什么用?

What is the usage of private static method in c#?

我有一个 public class 叫 MyClass.cs。它有 3 种方法:

 public class MyClass
 {
    public IEnumerable<MyDto> PublicA(bool useCache = true)
    {
    //Call an external resource
    //some code
    }

    public IEnumerable<AnotherDto> PublicB()
    {
    //some code
    var x= MyPrivateMethod(input);
    //some code
    }

    private IEnumerable<AnotherDto> MyPrivateMethod(IEnumerable<SomeDto>)
    {
    //return Mapped data from IEnumerable<SomeDto> to  IEnumerable<AnotherDto>

    }
 }

我使用 ReSharper 作为重构工具。它建议对 MyPrivateMethod 使用 static

private static IEnumerable<AnotherDto> MyPrivateMethod(IEnumerable<SomeDto>)

但是这个关键字在这里有什么用呢?由于该方法是私有的,不会在其他想要使用 MyClass 实例的 class 中使用。

我测试发现,当我为 MyPrivateMethod 使用 static 关键字时,我无法调用 class 的任何其他非私有静态方法。但是还不知道有什么用?例如,在存储或时间优化方面有什么好处吗?

根据 MSDN

Members that do not access instance data or call instance methods can be marked as static (Shared in Visual Basic). After you mark the methods as static, the compiler will emit nonvirtual call sites to these members. Emitting nonvirtual call sites will prevent a check at runtime for each call that makes sure that the current object pointer is non-null. This can achieve a measurable performance gain for performance-sensitive code. In some cases, the failure to access the current object instance represents a correctness issue.

https://msdn.microsoft.com/en-us/library/ms245046.aspx

另一个好处是调用序列,当您调用实例方法时,生成的代码会将 this 的实例作为第一个参数压入堆栈,该方法的其余参数将压入堆栈。因此,每个实例方法调用都需要为 this 以及其他方法参数再进行一次额外的堆栈推送。

如果将方法转换为静态方法,则静态方法调用不需要 this,因此 CPU 少了一次推送操作。单次调用好像没什么大用

但是如果您的方法将被频繁使用,并且如果您有几个不需要 this 的方法,那么它可以节省大量 CPU 时间,尤其是在图形和科学计算中。

这就是 Resharper 建议您在方法未引用属于 this 的任何内容时将方法更改为静态的原因。

这是示例,

    public int Add(int a, int b) {
        return a + b;
    }

    public static int StaticAdd(int a, int b) {
        return a + b;
    }

    public void InstanceAdd() {
        Console.WriteLine(this.Add(3,3));
    }

    public void InstanceAddStatic()
    {
        Console.WriteLine(StaticAdd(3, 3));
    }

这是为调用"InstanceAdd"

中的实例方法而生成的
.method public hidebysig 
    instance void InstanceAdd () cil managed 
{
    // Method begins at RVA 0x2095
    // Code size 16 (0x10)
    .maxstack 8

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: ldc.i4.3
    IL_0003: ldc.i4.3
    IL_0004: call instance int32 Temp.MathTest::Add(int32, int32)
    IL_0009: call void [System.Console]System.Console::WriteLine(int32)
    IL_000e: nop
    IL_000f: ret
} // end of method MathTest::InstanceAdd

这是为 "StaticAdd"

中的实例方法生成的 il
.method public hidebysig 
    instance void InstanceAddStatic () cil managed 
{
    // Method begins at RVA 0x20a6
    // Code size 15 (0xf)
    .maxstack 8

    IL_0000: nop
    IL_0001: ldc.i4.3
    IL_0002: ldc.i4.3
    IL_0003: call int32 Temp.MathTest::StaticAdd(int32, int32)
    IL_0008: call void [System.Console]System.Console::WriteLine(int32)
    IL_000d: nop
    IL_000e: ret
} // end of method MathTest::InstanceAddStatic

你看"StaticAdd",没有ldarg.0,就是this。对于每个方法调用,总会有 ldarg.0 作为第一条指令,然后是其余参数。