Domanda

Sto scrivendo un iteratore che deve passare attorno a un intero mutabile.

public IEnumerable<T> Foo(ref int valueThatMeansSomething)
{
    // Stuff

    yield return ...;
}

Questo mi dà " Errore 476 Gli iteratori non possono avere parametri ref o out " ;.

Ciò di cui ho bisogno è che questo valore intero sia modificato nell'iteratore e utilizzabile dal chiamante dell'iteratore. In altre parole, qualsiasi chiamata Foo() sopra desideri conoscere il valore finale di valueThatMeansSomething e ValueWrapper<T> può usarlo da solo. Voglio davvero un numero intero che sia un tipo di riferimento, non un tipo di valore.

L'unica cosa che mi viene in mente è scrivere una classe che incapsuli il mio numero intero e mi permetta di modificarlo.

public class ValueWrapper<T>
    where T : struct
{
    public ValueWrapper(T item)
    {
        this.Item = item;
    }

    public T Item { get; set; }
}

ValueWrapper<int> w = new ValueWrapper<int>(0);
foreach(T item in Foo(w))
{
    // Do stuff
}

if (w.Item < 0) { /* Do stuff */ }

Esiste qualche classe o meccanismo per gestirlo già nel BCL? Qualche difetto con foreach proposto sopra?

(Il mio uso effettivo è più complicato dell'esempio sopra, quindi gestire la variabile all'interno del mio <=> ciclo che chiama <=> non è un'opzione. Periodo.)

È stato utile?

Soluzione

No, sono abbastanza fiducioso che non esiste nulla nel BCL che possa farlo. La tua migliore opzione è proprio quello che hai proposto, credo. L'implementazione di ValueWrapper in realtà non deve essere più complicata di quella che hai proposto.

Naturalmente, non è garantito che sia thread-safe, ma se è necessario è possibile semplicemente convertire la proprietà automatica in una standard con una variabile di supporto e contrassegnare il campo come volatile (per assicurare che il valore sia sempre aggiornato).

Altri suggerimenti

Se hai solo bisogno di scrivere il valore, un'altra tecnica sarebbe:

public IEnumerable<whatever> Foo(Action<int> setter) { ... }

int value = 0;
foreach(var x in Foo(x => {value=x;}) { ... }

Per coincidenza, farò una serie sui motivi per cui ci sono così tante restrizioni sciocche sui blocchi di iteratori nel mio blog a luglio. " Perché nessun parametro ref? " sarà all'inizio della serie.

http://blogs.msdn.com/ericlippert/archive /tags/Iterators/default.aspx

Ho pensato a lungo che il BCL dovrebbe davvero avere una classe e un'interfaccia simile al seguente:

public delegate void ActByRef<T1,T2>(ref T1 p1);
public delegate void ActByRefRef<T1,T2>(ref T1 p1, ref T2 p2);
public interface IReadWriteActUpon<T>
{
  T Value {get; set;}
  void ActUpon(ActByRef<T> proc);
  void ActUpon<TExtraParam>(ActByRefRef<T, TExtraParam> proc, 
                           ref TExtraparam ExtraParam);
}

public sealed class MutableWrapper<T> : IReadWrite<T>
{
  public T Value;
  public MutableWrapper(T value) { this.Value = value; }
  T IReadWriteActUpon<T>.Value {get {return this.Value;} set {this.Value = value;} }
  public void ActUpon(ActByRef<T> proc)
  {
    proc(ref Value);
  }
  public void ActUpon<TExtraParam>(ActByRefRef<T, TExtraParam> proc, 
                           ref TExtraparam ExtraParam)
  {
    proc(ref Value, ref ExtraParam);
  }
}

Sebbene molte persone includano istintivamente i campi nelle proprietà automatiche, i campi spesso consentono un codice più pulito ed efficiente soprattutto quando si utilizzano tipi di valore. In molte situazioni, l'incapsulamento maggiore che si può ottenere utilizzando le proprietà può valere il costo in termini di efficienza e semantica, ma quando l'intero scopo di un tipo è quello di essere un oggetto di classe il cui stato è completamente esposto e mutevole, tale incapsulamento è controproducente.

L'interfaccia è inclusa non perché molti utenti di un MutableWrapper<T> vorrebbero invece utilizzare l'interfaccia, ma piuttosto perché un IReadWriteActUpon<T> potrebbe essere utile in una varietà di situazioni, alcune delle quali implicherebbero l'incapsulamento e qualcuno che ha un'istanza di <=> potrebbe voler passare al codice progettato per funzionare con dati incapsulati in un'interfaccia <=>.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top