Domanda

Mi trovo di tanto in tanto in C # 3.0 alla ricerca di modi per simulare il concetto di tupla. Nel corso del tempo ho avuto vari "poveri" implementazioni, eccone alcune:

Array di oggetti di base :

object[] poorTuple = new object[]{foo,bar,baz}; // basic object array

Più fortemente tipizzato , HoHoHo ...

KeyValuePair<TypeA, KeyValuePair<TypeB, TypeC>> poorTuple;

Implementazione di una classe che può utilizzare l'inferenza del tipo (estrapolata da Programmazione funzionale per Mondo reale )

public static class Tuple{
  public static Tuple<T1, T2> Create<T1 foo, T2 bar>{
    return new Tuple<T1, T2>(foo, bar);
  }
}
// later: 
var data = Tuple.Create("foo", 42);

Domande:

  1. Qualsiasi altro modo per avere la tupla di un uomo povero in C # 3.0 (o linguaggio di scelta privo della struttura dei dati).

  2. Qual è il modo migliore per ottenere una tupla in C # 3.0 - se qualcuno ha una raccomandazione per la biblioteca, è il benvenuto.

  3. A che punto (sì, generalizza per me) ha senso creare un tipo specifico piuttosto che qualcosa come un elenco o una tupla? (in cerca di regole empiriche)

È stato utile?

Soluzione

Puoi creare tipi anonimi che funzionano in modo simile alle tuple, tranne con nomi utili:

var itemsWithChildCounts 
    = myObjects.Select(x => new { Name = x.Name, Count = x.Children.Count() });

Altri suggerimenti

Ecco il codice per una tupla generica presa da articolo nell'edizione di aprile 2007 di Visual Studio Magazine .

public struct Tuple<T1, T2> : IEquatable<Tuple<T1, T2>>
{
    private readonly T1 first;
    public T1 First
    {
        get { return first; }
    }

    private readonly T2 second;
    public T2 Second
    {
        get { return second; }
    } 

    public Tuple(T1 f, T2 s)
    {
        first = f;
        second = s;
    }

    #region IEquatable<Tuple<T1,T2>> Members
    public bool Equals(Tuple<T1, T2> other)
    {
        return first.Equals(other.first) && 
            second.Equals(other.second);
    }

    public override bool Equals(object obj)
    {
        if (obj is Tuple<T1, T2>)
            return this.Equals((Tuple<T1, T2>)obj);
        else
            return false;
    }

    public override int GetHashCode()
    {
        return first.GetHashCode() ˆ second.GetHashCode();
    }
    #endregion
}

Per 1 - 2: preferisco implementare la tua classe tupla. L'implementazione che hai rubato è decente. Dovrebbe funzionare bene.

Per 3: ecco la mia regola empirica: non appena riuserai a riutilizzare questa funzionalità in più metodi (con gli stessi tipi con lo stesso significato) o se la usi in qualsiasi API pubblica, penso che sia tempo di implementare un "reale" classe con i tuoi tipi specifici.

  1. Il " Implementare una classe " il metodo è buono come sarà (e dovrebbe essere comunque nella prossima versione di .NET)
  2. Nessuna idea, per ora li tengo nella mia biblioteca personale di lezioni.
  3. Prenderei in considerazione la creazione di una classe adeguata per loro non appena vengono esposti al pubblico (ovvero quando non vengono più utilizzati solo per memorizzare internamente i valori correlati per una classe).

Dato che hai chiesto un'opinione, la mia sarebbe quella di creare sempre un tipo - non riesco a capire un motivo per non farlo.

Il più delle volte puoi scoprire che hai effettivamente bisogno del tipo (l'uso principale è quello di archiviare due articoli in una raccolta o restituire due articoli da una chiamata del metodo - in entrambi i casi se gli articoli non sono strettamente correlati , probabilmente stai facendo qualcosa di sbagliato).

Penso che sia utile creare un nuovo tipo quando ha senso introdurre un nuovo set di valori nel tuo programma. Ad esempio, se stai scrivendo una calcolatrice complessa, crea un tipo di numero complesso. Se vuoi davvero solo " colla " alcune variabili insieme per un momento, quindi una tupla è probabilmente una scelta migliore. Diciamo che hai una semplice funzione che raccoglie due numeri dalla console ... potresti fare qualcosa del genere:

static void GetNumbers(out int x, out int y) { ... }
...
int x, y;
GetNumbers(out x, out y);

Penso che di solito abbia senso quando un " getter " La funzione ha un valore di ritorno, ma in questo caso non lo è perché non posso davvero avere due valori di ritorno. Potrei andare a creare un nuovo tipo chiamato TwoNumbers e usarlo, ma penso che questo diventi rapidamente più un problema che una soluzione. Se C # avesse tuple potrei essere in grado di fare qualcosa del tipo:

static (int, int) GetNumbers() { ... }
...
int x, y;
(x, y) = GetNumbers();

Ora la domanda davvero interessante è: sebbene C # non abbia questa funzione, sono in grado di implementarla da solo con una libreria? Il codice che suggerisci è un inizio ma non mi consente di assegnare come ho fatto nel secondo esempio. Non sono sicuro di C # ma puoi davvero avvicinarti a questo in C ++ usando il fatto che una chiamata di funzione può essere l'operando di sinistra per l'operatore di assegnazione quando il suo valore di ritorno è un tipo di riferimento . Considera quanto segue:

// this class is implemented much like yours only with C++
template<typename T1, typename T2> class tuple { ... }
...
template<typename T1, typename T2> tuple<T1, T2>& tie(T1 a, T2 b) { ... }
...
template<typename T1, typename T2> tuple<T1, T2> get_numbers() { ... }
...
int x, y;
tie(x, y) = get_numbers();

Direi che è dannatamente vicino ... invece di (x, y) = abbiamo tie (x, y) = . Se sei interessato ai dettagli di implementazione, ti rimando alla libreria TR1 dove ho appreso per la prima volta questo:

http: //www.boost .org / doc / librerie / 1_41_0 / librerie / tupla / doc / tuple_users_guide.html # livelli

Quindi, per riportare tutto questo in C # 3.0 ... possiamo certamente creare una classe di tupla generica come hai mostrato, ma possiamo creare una funzione come il legame a & un; unpack " la tupla in C #? Non l'ho provato, sembra divertente. Senza qualcosa del genere, sarei riluttante a far proliferare una libreria di tuple in C # attraverso il mio codice.

Non mi piace l'inferenza del tipo in C # poiché è abusato troppo per la scrittura più breve. Naturalmente è una funzionalità molto interessante, ma le persone lo abusano di IMHO come in questo caso.

In questo caso specificherei esplicitamente il tipo per evitare confusioni sul tipo (cioè forse 42 è un lungo, o un byte o un corto).

Quindi perché non avere una semplice classe tupla, che può essere implementata in poche righe. E se sei pigro puoi anche scrivere alcuni metodi di estensione per la tua classe tupla. Questo rende la vita più semplice ma anche più pulita.

Non vedo il punto di avere una "fantasia" classe tupla invece di quella generica che hai presentato (ad eccezione dell'inferenza di tipo).

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