Utilizzando Case / Switch e GetType per determinare l'oggetto [duplicato]
-
22-08-2019 - |
Domanda
Eventuali duplicati:
C # - Esiste una migliore alternativa di questo per 'interruttore del tipo'?
Se si vuole switch
su un tipo di oggetto, qual è il modo migliore per fare questo?
Codice frammento
private int GetNodeType(NodeDTO node)
{
switch (node.GetType())
{
case typeof(CasusNodeDTO):
return 1;
case typeof(BucketNodeDTO):
return 3;
case typeof(BranchNodeDTO):
return 0;
case typeof(LeafNodeDTO):
return 2;
default:
return -1;
}
}
So che questo non funziona in questo modo, ma mi chiedevo come si potrebbe risolvere questo problema.
È una dichiarazione if/else
appropriata in questo caso?
O si utilizza l'opzione e aggiungere .ToString()
al tipo?
Soluzione
Se I davvero ha dovuto switch
sul tipo di oggetto, userei .ToString()
. Tuttavia, vorrei evitare a tutti i costi: IDictionary<Type, int>
farà molto meglio, visitatore potrebbe essere un eccessivo ma per il resto è ancora un perfettamente bene soluzione.
Altri suggerimenti
Questo non risolverà il problema direttamente, come si vuole accendere i propri tipi definiti dall'utente, ma per il bene degli altri che vogliono solo accendere il built-in tipi, è possibile utilizzare il TypeCode enumerazione:
switch (Type.GetTypeCode(node.GetType()))
{
case TypeCode.Decimal:
// Handle Decimal
break;
case TypeCode.Int32:
// Handle Int32
break;
...
}
Nel post sul blog MSDN molte domande: Interruttore sul tipo è il motivo per cui alcune informazioni sul .NET non fornisce accensione tipi.
Come al solito -. Workaround esiste sempre
Questa non è mia, ma purtroppo ho perso la fonte. Rende l'accensione tipi possibili, ma io personalmente penso che sia abbastanza imbarazzante (l'idea dizionario è meglio):
public class Switch
{
public Switch(Object o)
{
Object = o;
}
public Object Object { get; private set; }
}
/// <summary>
/// Extensions, because otherwise casing fails on Switch==null
/// </summary>
public static class SwitchExtensions
{
public static Switch Case<T>(this Switch s, Action<T> a)
where T : class
{
return Case(s, o => true, a, false);
}
public static Switch Case<T>(this Switch s, Action<T> a,
bool fallThrough) where T : class
{
return Case(s, o => true, a, fallThrough);
}
public static Switch Case<T>(this Switch s,
Func<T, bool> c, Action<T> a) where T : class
{
return Case(s, c, a, false);
}
public static Switch Case<T>(this Switch s,
Func<T, bool> c, Action<T> a, bool fallThrough) where T : class
{
if (s == null)
{
return null;
}
T t = s.Object as T;
if (t != null)
{
if (c(t))
{
a(t);
return fallThrough ? s : null;
}
}
return s;
}
}
Utilizzo:
new Switch(foo)
.Case<Fizz>
(action => { doingSomething = FirstMethodCall(); })
.Case<Buzz>
(action => { return false; })
mi basta usare un'istruzione if. In questo caso:
Type nodeType = node.GetType();
if (nodeType == typeof(CasusNodeDTO))
{
}
else ...
L'altro modo per farlo è:
if (node is CasusNodeDTO)
{
}
else ...
Il primo esempio è vero per i tipi esatte solo, quando quest'ultimo verifica la presenza di eredità troppo.
Sono di fronte con lo stesso problema e sono imbattuto in questo post. È questo ciò che si intende con l'approccio IDictionary:
Dictionary<Type, int> typeDict = new Dictionary<Type, int>
{
{typeof(int),0},
{typeof(string),1},
{typeof(MyClass),2}
};
void Foo(object o)
{
switch (typeDict[o.GetType()])
{
case 0:
Print("I'm a number.");
break;
case 1:
Print("I'm a text.");
break;
case 2:
Print("I'm classy.");
break;
default:
break;
}
}
Se è così, non posso dire che io sono un fan di conciliare i numeri nel dizionario con le istruzioni case.
Questo sarebbe l'ideale ma il riferimento dizionario uccide:
void FantasyFoo(object o)
{
switch (typeDict[o.GetType()])
{
case typeDict[typeof(int)]:
Print("I'm a number.");
break;
case typeDict[typeof(string)]:
Print("I'm a text.");
break;
case typeDict[typeof(MyClass)]:
Print("I'm classy.");
break;
default:
break;
}
}
C'è un'altra implementazione ho trascurato?
Si può fare questo:
if (node is CasusNodeDTO)
{
...
}
else if (node is BucketNodeDTO)
{
...
}
...
Anche se sarebbe più elegante, è forse non così efficace come alcune delle altre risposte qui.
Si può fare questo:
function void PrintType(Type t) {
var t = true;
new Dictionary<Type, Action>{
{typeof(bool), () => Console.WriteLine("bool")},
{typeof(int), () => Console.WriteLine("int")}
}[t.GetType()]();
}
E 'chiaro e la sua facile. E 'un po' più lento di cache il dizionario da qualche parte .. ma per un sacco di codice di questo non importa comunque ..
Un approccio è quello di aggiungere un metodo puro GetNodeType virtuale () per NodeDTO e sovrascrivere nelle discendenti in modo che ogni discendente ritorna tipo effettivo.
A seconda di cosa si sta facendo nella dichiarazione switch, la risposta corretta è il polimorfismo. Basta mettere una funzione virtuale nella / classe base interfaccia e sovrascrivere per ogni tipo di nodo.
Io in realtà preferisco l'approccio dato come la risposta qui: C'è un'alternativa migliore di questo a 'interruttore del tipo'?
V'è tuttavia un buon argomento di non attuare alcun tipo di confronto methids in un linguaggio orientato agli oggetti come C #. Si potrebbe in alternativa estendere e aggiungere altre funzionalità desiderata usare l'ereditarietà.
Questo punto è stato discusso nei commenti degli autori blog qui: http: // blog. msdn.com/b/jaredpar/archive/2008/05/16/switching-on-types.aspx#8553535
Ho trovato questo un punto estremamente interessante che ha cambiato il mio approccio in una situazione simile e spero solo che questa aiuta gli altri.
Cordiali saluti, Wayne