Jeśli chcesz powrócić zarówno iterator i int od wybranej metody, obejście tego problemu jest taka:
public class Bar : IFoo
{
public IEnumerable<int> GetItems(ref int somethingElse)
{
somethingElse = 42;
return GetItemsCore();
}
private IEnumerable<int> GetItemsCore();
{
yield return 7;
}
}
Należy pamiętać, że żaden z kodem wewnątrz metoda iteratora (tzn. zasadniczo metoda zawierająca yield return
lub yield break
) jest wykonywana do momentu wywołania metody MoveNext()
w module wyliczającym. Więc jeśli jesteś w stanie wykorzystać out
lub ref
w metodzie iteracyjnej, co można uzyskać zaskakujące zachowanie takiego:
// This will not compile:
public IEnumerable<int> GetItems(ref int somethingElse)
{
somethingElse = 42;
yield return 7;
}
// ...
int somethingElse = 0;
IEnumerable<int> 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
Jest to typowy pułapka, powiązany kwestia jest taka:
public IEnumerable<int> GetItems(object mayNotBeNull){
if(mayNotBeNull == null)
throw new NullPointerException();
yield return 7;
}
// ...
IEnumerable<int> items = GetItems(null); // <- This does not throw
items.GetEnumerators().MoveNext(); // <- But this does
tak dobrym sposobem jest oddzielenie metod iteratora na dwie części: jedną do natychmiastowego wykonania i jedną zawierającą kod, który powinien być leniwie wykonany.
public IEnumerable<int> GetItems(object mayNotBeNull){
if(mayNotBeNull == null)
throw new NullPointerException();
// other quick checks
return GetItemsCore(mayNotBeNull);
}
private IEnumerable<int> GetItemsCore(object mayNotBeNull){
SlowRunningMethod();
CallToDatabase();
// etc
yield return 7;
}
// ...
IEnumerable<int> items = GetItems(null); // <- Now this will throw
EDIT: Jeśli naprawdę chcesz zachowanie gdzie przesuwając iterator byłoby zmodyfikować ref
-parameter, można zrobić coś takiego:
public static IEnumerable<int> GetItems(Action<int> setter, Func<int> getter)
{
setter(42);
yield return 7;
}
//...
int local = 0;
IEnumerable<int> items = GetItems((x)=>{local = x;},()=>local);
Console.WriteLine(local); // 0
items.GetEnumerator().MoveNext();
Console.WriteLine(local); // 42
Czy coś się stało, gdy próbowaliście tego, czy też prosiliście nas o uzasadnienie wypróbowania? –
Omawiam niektóre z tych zagadnień dotyczących projektowania: http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx –
nowoczesne rozwiązanie : http://answers.unity3d.com/answers/551381/view.html – Fattie