Si consideri il seguente codice (pesantemente semplificato):tipizzazione condizionale nel metodo generico
public T Function<T>() {
if (typeof(T) == typeof(string)) {
return (T) (object) "hello";
}
...
}
E 'una specie di assurdo primo cast a object
, poi a T
. Ma il compilatore non ha modo di sapere che il test precedente assicurato T
è di tipo string
.
Qual è il modo più elegante e idiomatico per ottenere questo comportamento in C# (che include l'eliminazione dello stupido typeof(T) == typeof(string)
, dal momento che T is string
non può essere utilizzato)?
Addendum: Non v'è alcun tipo di ritorno varianza .net, quindi non è possibile fare un sovraccarico di funzioni di tipo stringa (che, tra l'altro, è solo un esempio, ma uno dei motivi per cui un'associazione la ridefinizione finale nel polimorfismo, ad es. UML, non può essere eseguita in C#). Ovviamente, il seguente sarebbe grande, ma non funziona:
public T Function<T>() {
...
}
public string Function<string>() {
return "hello";
}
Calcestruzzo Esempio 1: Perché c'è stato diversi attacchi al fatto che una funzione generica che mette alla prova per i tipi specifici ISN' t generico, cercherò di fornire un esempio più completo. Considera il modello di design di tipo quadrato. Qui di seguito un frammento:
public class Entity {
Dictionary<PropertyType, object> properties;
public T GetTypedProperty<T>(PropertyType p) {
var val = properties[p];
if (typeof(T) == typeof(string) {
(T) (object) p.ToString(this); // magic going here
}
return (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(val);
}
}
Calcestruzzo Esempio 2: consideri il modello di progettazione Interprete:
public class Expression {
public virtual object Execute() { }
}
public class StringExpression: Expression {
public override string Execute() { } // Error! Type variance not allowed...
}
Ora cerchiamo di usare farmaci generici in esecuzione per consentire al chiamante di forzare un tipo di ritorno:
public class Expression {
public virtual T Execute<T>() {
if(typeof(T) == typeof(string)) { // what happens when I want a string result from a non-string expression?
return (T) (object) do_some_magic_and_return_a_string();
} else if(typeof(T) == typeof(bool)) { // what about bools? any number != 0 should be True. Non-empty lists should be True. Not null should be True
return (T) (object) do_some_magic_and_return_a_bool();
}
}
}
public class StringExpression: Expressiong {
public override T Execute<T>() where T: string {
return (T) string_result;
}
}
Sono curioso .. si può spiegare un po 'che tipo di valori che si sta per tornare, per esempio da dove vengono e ci sono dei vincoli espliciti o espliciti sulla funzione? dobbiamo supporre che sono previsti solo tipi intrinseci? –
Come ho sottolineato in un commento qui sotto, ci sono situazioni in cui il chiamante si aspetta perfettamente una semantica diversa per la funzione tra diversi tipi. Ad esempio, diverse lingue supportano l'operatore + per numeri interi e stringhe; e tuttavia, per i numeri interi funge da somma, mentre per le stringhe funge da concatenatore. –
Se ti interessa una situazione ho bisogno di questo modello (badate bene, ho visto questo accadere diverse volte in contesti diversi), ho un 'Valuta' di una classe chiamata 'Expression', che mappa l'AST di un DSL. La lingua sottostante è digitata dinamicamente, quindi il chiamante non conosce esattamente il tipo 'Valuta '. Ma se il chiamante forza un tipo specifico, ad es. 'Valuta ', quindi la funzione può aggiungere un po 'di "zucchero semantico", come test per 'nulls', numeri maggiori di 0, liste non vuote, ecc. Il chiamante aspetta un' bool', indipendentemente da cosa succede all'interno. –