Domanda

Ho un namespace di struct che rappresentano diverse unità di misura (metri, piedi, pollici, ecc) ... anout 12 in totale, per gentile concessione di generare modelli T4 :).

Ogni porta struct operatori di cast impliciti per sostenere casting del valore di qualsiasi altra misurazione value-type, quindi il seguente sytax è legale:

var oneThousandMeters = new Meters(1000);    
Kilometers aKilo = oneThousandMeters ;     // implicit cast OK. Value = 1 Km

Per aggiungere alla gioia, c'è un catch-all classe chiamata Distanza , che può contenere qualsiasi unità di misura, e può anche essere implicitamente espressi da e per e valore di misura ...

var magnum = new Distance(12, DistanceUnits.Inches); 
Feet wifesDelight = magnum;               // implicit cast OK. Value = 1 foot.

Seguendo lo standard framework NET, tutte le stringhe di formattazione e l'analisi è gestito da un formatProvider esterno, che implementa ICustomFormatter. Purtroppo, questo significa che il valore è inscatolato quando viene passato al metodo Format, e le esigenze metodo formato per testare l'oggetto con ogni tipo misura chiamata prima che possa agire su di esso. Internamente, il metodo Format appena getta la misura per un valore di distanza in ogni caso, ecco arriva la domanda ....

Domanda:

public string Format(string format, object arg, IFormatProvider formatProvider)
{
    Distance distance;           

    // The following line is desired, but fails if arg != typeof(Distance)   
    distance = (Distance)arg;    

    // But the following tedious code works:
    if(arg is Distance)
       distance = (Distance)arg;
    else if(arg is Meters)
       distance = (Distance)(Meters)arg;     // OK. compile uses implicit cast. 
    else if(arg is Feet)
       distance = (Distance)(Feet)arg;       // OK. compile uses implicit cast. 
    else if(arg is Inches)
       distance = (Distance)(Inches)arg;     // OK. compile uses implicit cast. 
    else
        ... // tear you hair out for all 12 measurement types
}

Ci sono delle soluzioni per questo, o è solo uno di quei difetti irrisolvibili di tipi di valore?

PS: Ho controllato questo post , e anche se la questione è simile, non è quello che sto cercando.

È stato utile?

Soluzione

Beh, è ??una questione di separare la conversione unboxing dalla conversione definita dall'utente. Si vuole sia che si verifichi - e si deve specificare il tipo di unboxing, oltre che far conoscere al compilatore quando si vuole una conversione definita dall'utente. La conversione definita dall'utente ha di essere raccolti a di compilazione tempo a meno che si sta utilizzando la tipizzazione dinamica, così le esigenze del compilatore per sapere quale tipo si sta cercando di convertire da.

Una possibilità è quella di avere un IDistance interfaccia , che tutte le struct attuare. Allora si potrebbe utilizzare:

IDistance distanceArg = arg as IDistance;
if (distanceArg != null)
{
    Distance distance = distanceArg.ToDistance();
}

Come hai già un valore in scatola, utilizzando un'interfaccia non causerà la boxe in più o qualcosa di simile. Ogni implementazione ToDistance probabilmente può semplicemente usare la conversione implicita:

public Distance ToDistance()
{
    return this;
}

... o si potrebbe fare l'ToDistance uso di conversione.

Altri suggerimenti

Sì è solo una di quelle cose che devi convivere.

Si esegue nella stessa cosa se si infilano un intero in un oggetto:

int a = 0;
object b = a;
int c = (int)b; // this works
short d = (short)b; // this fails
short e = (short)(int)b; // this works
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top