Какое использование частного статического метода в С #?

У меня есть открытый класс 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 как инструмент рефакторинга. Предлагается использовать static вместо MyPrivateMethod.

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

Но как здесь используется это ключевое слово? Поскольку метод является частным и не будет использоваться в другом классе, который хочет использовать экземпляр MyClass.

Я протестировал и обнаружил, что, когда я использую ключевое слово static для MyPrivateMethod, я не могу вызывать какие-либо другие методы класса, которые НЕ являются частными статическими. Но все же я не знаю, каково использование? Есть ли какая-то выгода, например, от хранения или оптимизации времени?


person Elnaz    schedule 06.01.2018    source источник
comment
Это ясно дает понять, что это не связано ни с каким конкретным экземпляром MyClass. Вообще говоря, если метод логически не связан с конкретным экземпляром, его static делает это более понятным. Это также означает, что вы можете вызывать его из других статических методов без необходимости получать ссылку на экземпляр.   -  person Jon Skeet    schedule 06.01.2018
comment
Я протестировал и обнаружил, что, когда я использую ключевое слово static для MyPrivateMethod, я не могу вызывать какие-либо другие методы класса, которые НЕ являются частными статическими. Тогда ваше тестирование было неполным. private static методы могут обращаться к любым другим статическим методам в классе, независимо от того, являются они частными или нет.   -  person JLRishe    schedule 06.01.2018
comment
Вы сказали: «Если сделать статичнее, это станет яснее». Вы имеете в виду, что это полезно только для проверки кода и не влияет на производительность? Также вы сказали: «Вы можете вызывать его из других статических методов без необходимости получать ссылку на экземпляр». Когда метод является частным, у меня нет доступа из другого класса   -  person Elnaz    schedule 06.01.2018
comment
ReSharper видит, что вы используете MyPrivateMethod для совместного использования кода с другими методами вашего класса, замечает, что метод в настоящее время не имеет доступа ни к каким нестатическим методам или полям, и предлагает добавить static в свое объявление. Он пытается угадать ваше намерение создать вспомогательный метод, вместо того, чтобы определять ваше решение.   -  person Sergey Kalinichenko    schedule 06.01.2018
comment
@Elnaz Я не совсем понимаю, что вы только что сказали, но да, private static методы могут вызывать любой другой статический метод в классе. См. Здесь: ideone.com/ijLhEr   -  person JLRishe    schedule 06.01.2018
comment
Статический - это статический независимо от того, public или private. Вы неправильно поняли, что static вы не можете вызывать какой-либо нестатический метод в static методе. لنک زیر   -  person Aria    schedule 06.01.2018


Ответы (1)


Согласно MSDN

Члены, которые не имеют доступа к данным экземпляра или вызывают методы экземпляра, могут быть помечены как статические (общие в Visual Basic). После того, как вы отметите методы как статические, компилятор отправит этим членам невиртуальные сайты вызовов. Создание невиртуальных сайтов вызовов предотвратит проверку во время выполнения каждого вызова, которая гарантирует, что текущий указатель объекта не равен нулю. Это может обеспечить измеримый прирост производительности для кода, чувствительного к производительности. В некоторых случаях невозможность доступа к текущему экземпляру объекта представляет собой проблему правильности.

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

Еще одно преимущество - это вызов последовательности: когда вы вызываете метод экземпляра, сгенерированный код помещает экземпляр this в стек в качестве первого параметра, а остальные параметры метода будут помещены в стек. Таким образом, каждый вызов метода экземпляра требует еще одного дополнительного нажатия стека для this вместе с другими параметрами метода.

Если вы преобразовываете свой метод в статический, вызовы статических методов не требуют this, поэтому на одну операцию push для ЦП меньше. Это не кажется большим преимуществом для одного звонка.

Но если ваш метод будет использоваться очень часто и если у вас есть несколько методов, которые не требуют this, то он может значительно сэкономить время ЦП, особенно в графических и научных расчетах.

По этой причине 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

и это il, созданный, например, метод в "StaticAdd"

.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 в качестве первой инструкции, а затем последуют остальные параметры.

person Akash Kava    schedule 06.01.2018
comment
Спасибо. У вас есть ссылка, которая поможет мне лучше понять это? В частности, по поводу вашего первого абзаца. - person Elnaz; 06.01.2018
comment
Я почти уверен, что причина, по которой Resharper рекомендует это, не имеет ничего общего с экономией ЦП из-за отсутствия this в стеке. - person JLRishe; 06.01.2018
comment
@JLRishe, вы хотите сказать, что нет никакой выгоды от экономии ресурсов процессора при использовании статического метода? - person Akash Kava; 06.01.2018
comment
@AkashKava Нет, я хочу сказать, что не думаю, что описанная вами ситуация является причиной, которую предлагает Resharper, по крайней мере, не единственной причиной (вы утверждали, что это была причина Resharper в последнем абзаце) . У вас есть цитата, объясняющая причины, по которым они рекомендовали это? - person JLRishe; 06.01.2018
comment
@JLRishe msdn.microsoft.com/en-us/library/ms245046.aspx проверьте описание правила, однако это MSDN, но я уверен, что ребята из Resharper следуют этому как набору правил. - person Akash Kava; 06.01.2018
comment
@AkashKava Объяснение на этой странице MSDN совершенно не связано с причиной, указанной в вашем ответе. - person JLRishe; 06.01.2018
comment
@JLRishe да, я согласен, я обновил свой ответ, и я также добавил примеры il в качестве дополнительного преимущества. - person Akash Kava; 06.01.2018