Почему методы итератора не могут принимать параметры ref или out?

Если вы хотите вернуть итератор parameter и int из вашего метода, обходной params путь:

public class Bar : IFoo
{
    public IEnumerable GetItems( ref int somethingElse )
    {
        somethingElse = 42;
        return GetItemsCore();
    }

    private IEnumerable GetItemsCore();
    {
        yield return 7;
    }
}

Следует отметить, что c-sharp ни один код внутри метода ref итератора (т.е. в основном parameters метод, содержащий yield return или yield break) не c-sharp выполняется до тех пор, пока .cs-file не будет вызван метод MoveNext() в .cs-file перечислителе. Итак, если csharp бы вы могли использовать c# out или ref в своем методе итератора, вы params бы получили такое удивительное out поведение:

// This will not compile:
public IEnumerable GetItems( ref int somethingElse )
{
    somethingElse = 42;
    yield return 7;
}

// ...
int somethingElse = 0;
IEnumerable items = GetItems( ref somethingElse );
// at this point somethingElse would still be 0
items.GetEnumerator().MoveNext();
// but now the assignment would be executed and somethingElse would be 42

Это распространенная visual-c# ошибка, связанная с этим .cs-file проблема:

public IEnumerable GetItems( object mayNotBeNull ){
  if( mayNotBeNull == null )
    throw new NullPointerException();
  yield return 7;
}

// ...
IEnumerable items = GetItems( null ); // <- This does not throw
items.GetEnumerators().MoveNext();                    // <- But this does

Таким образом, хороший visual-c# шаблон - разделить методы params итератора на две части: одну ref для немедленного выполнения c#.net и другую, содержащую код, который c#-language должен выполняться лениво.

public IEnumerable GetItems( object mayNotBeNull ){
  if( mayNotBeNull == null )
    throw new NullPointerException();
  // other quick checks
  return GetItemsCore( mayNotBeNull );
}

private IEnumerable GetItemsCore( object mayNotBeNull ){
  SlowRunningMethod();
  CallToDatabase();
  // etc
  yield return 7;
}    
// ...
IEnumerable items = GetItems( null ); // <- Now this will throw

ИЗМЕНИТЬ: Если params вам действительно нужно поведение, при c#-language котором перемещение итератора c-sharp изменяет параметр ref, вы можете parameter сделать что-то вроде этого:

public static IEnumerable GetItems( Action setter, Func getter )
{
    setter(42);
    yield return 7;
}

//...

int local = 0;
IEnumerable items = GetItems((x)=>{local = x;}, ()=>local);
Console.WriteLine(local); // 0
items.GetEnumerator().MoveNext();
Console.WriteLine(local); // 42

c#

parameters

ref

out

2022-06-10T09:29:10+00:00