multiple - usando la palabra clave ''is'' en un interruptor en c#
switch case c++ (10)
En C # no es posible utilizar la palabra clave "es" como parte de una declaración de cambio. Todas las etiquetas de casos en un interruptor deben evaluar expresiones constantes. "is" no es convertible a una expresión constante.
Definitivamente siento dolor cuando se trata de encender tipos. Porque realmente la solución que delineó funciona, pero es una forma convencida de decir para x do y, y a do b. Sería mucho más natural escribirlo más como el siguiente
TypeSwitch.Do(
sender,
TypeSwitch.Case<Button>(() => textBox1.Text = "Hit a Button"),
TypeSwitch.Case<CheckBox>(x => textBox1.Text = "Checkbox is " + x.Checked),
TypeSwitch.Default(() => textBox1.Text = "Not sure what is hovered over"));
Aquí hay una publicación de blog que escribí sobre cómo lograr esta funcionalidad.
http://blogs.msdn.com/jaredpar/archive/2008/05/16/switching-on-types.aspx
Actualmente estoy agregando algunas nuevas clases ampliadas a este código:
foreach (BaseType b in CollectionOfExtendedTypes) {
if (b is ExtendedType1) {
((ExtendedType1) b).foo = this;
}
else if (b is ExtendedType2) {
((ExtenedType2) b).foo = this;
}
else {
b.foo = this;
}
}
y tenía curiosidad por saber si hay una forma de utilizar la funcionalidad de palabra clave is
en una declaración de cambio?
En C #, creo que la sentencia switch solo funciona con enteros y cadenas.
En realidad, los conmutadores no coinciden con una variable (cadena o int (o enum)) con una expresión constante como la instrucción switch.
http://msdn.microsoft.com/en-us/library/06tc147t(VS.71).aspx
Hay otra cosa en que pensar además de la forma en que el compilador maneja las sentencias switch
, y ese es el funcionamiento del operador is
. Hay una gran diferencia entre:
if (obj is Foo)
y
if (obj.GetType() == typeof(Foo))
A pesar del nombre, el operador is
le dice si un objeto es compatible con un tipo dado, no si es del tipo dado. Esto lleva a errores no del todo obvios (aunque este es bastante obvio) que se ven así:
if (obj is System.Object)
{
//this will always execute
}
else if (obj is Foo)
{
//this will never execute
}
Muchas de las sugerencias aquí lo señalan en la dirección de usar el tipo del objeto. Eso está bien si lo que realmente quieres es lógica asociada con cada tipo. Pero si ese es el caso, camine con cuidado cuando use el operador is
.
Además: aunque no puedes modificar estos tipos básicos, eso no significa que no puedas usar la sugerencia de Owen. Podría implementar métodos de extensión:
public enum MyType { Foo, Bar, Baz };
public static class MyTypeExtension
{
public static MyType GetMyType(this Foo o)
{
return MyType.Foo;
}
public static MyType GetMyType(this Bar o)
{
return MyType.Bar;
}
public static MyType GetMyType(this Baz o)
{
return MyType.Baz;
}
}
Entonces puede usar una declaración de switch
:
switch (myObject.GetType())
{
case MyType.Foo:
// etc.
Podría agregar un método getType()
a BaseType
implementado por cada subclase concreta para devolver una identificación integral única (posiblemente una enumeración) y activar eso, ¿sí?
Si bien no es posible usar la instrucción switch para verificar tipos, no es imposible reducir el problema a una base de código más manejable.
Dependiendo de la situación específica y el requisito que consideraría.
Usar
IDictionary<Type, T>
para almacenar el resultado en un diccionario. T podría ser un delegado al que puedas llamar. Esto funcionará si no tiene que preocuparse por la herencia. Restaurar la herencia requerirá un poco más de trabajo.Usando el nombre de tipo de la clase (que es una cadena) dentro de la declaración de cambio. Utiliza el
switch (b.GetType().Name)
y no hay ninguna opción para la estructura de herencia profunda.
Los casos de tipo y el código orientado a objetos no parecen encajar bien en mi experiencia. El enfoque que prefiero en esta situación es el patrón de despacho doble . En breve:
- Cree un tipo de oyente con un proceso de método virtual vacío (ExtendedTypeN arg) para cada tipo extendido que vaya a enviar.
- Agregue un método virtual de envío (oyente de escucha) al tipo de base que toma un oyente como argumento. Su implementación será llamar a listener.Process ((Base) this).
- Utilice el método Dispatch en cada tipo extendido para llamar a la sobrecarga apropiada de Process en el tipo de escucha.
- Extienda el tipo de oyente anulando el método de proceso apropiado para cada subtipo que le interese.
El argumento arrastrando los pies baila eliminando el molde de reducción al doblarlo en la llamada a Despacho: el receptor conoce su tipo exacto y lo comunica llamando la sobrecarga exacta de Proceso para su tipo. Esta es también una gran ganancia de rendimiento en implementaciones como .NET Compact Framework, en el que los lanzamientos estrechos son extremadamente lentos, pero el despacho virtual es rápido.
El resultado será algo como esto:
public class Listener
{
public virtual void Process(Base obj) { }
public virtual void Process(Derived obj) { }
public virtual void Process(OtherDerived obj) { }
}
public class Base
{
public virtual void Dispatch(Listener l) { l.Process(this); }
}
public class Derived
{
public override void Dispatch(Listener l) { l.Process(this); }
}
public class OtherDerived
{
public override void Dispatch(Listener l) { l.Process(this); }
}
public class ExampleListener
{
public override void Process(Derived obj)
{
Console.WriteLine("I got a Derived");
}
public override void Process(OtherDerived obj)
{
Console.WriteLine("I got an OtherDerived");
}
public void ProcessCollection(IEnumerable collection)
{
foreach (Base obj in collection) obj.Dispatch(this);
}
}
Esto realmente parece una situación para una buena implementación polimórfica. Si anula los métodos apropiados en las clases derivadas, puede que no necesite los controles en el bucle.
La última versión de C # (7) ahora incluye esta funcionalidad
El patrón de tipo permite una evaluación y conversión de tipo concisa. Cuando se utiliza con la instrucción switch para realizar la coincidencia de patrones, prueba si una expresión se puede convertir a un tipo especificado y, si puede ser, lo convierte en una variable de ese tipo. Su sintaxis es:
case type varname