2010-10-31 7 views
10

¿Cómo puedo comprobar/Evaluar el tipo exacto de T sin un objeto para T. Sé que mi pregunta tal vez confuso, pero considere esto ...Genéricos: ¿Cómo comprobar el tipo exacto de T, sin objeto para T

public abstract class Business 
    { 
     public abstract string GetBusinessName(); 
    } 

    public class Casino : Business 
    { 
     public override string GetBusinessName() 
     { 
      return "Casino Corp"; 
     } 
    } 

    public class DrugStore : Business 
    { 
     public override string GetBusinessName() 
     { 
      return "DrugStore business"; 
     } 
    } 


    public class BusinessManager<T> where T : Business 
    { 
     private Casino _casino; 
     private DrugStore _drugStore; 

     public string ShowBusinessName() 
     { 
      string businessName; 
      if (T == Casino) // Error: How can I check the type? 
      { 
       _casino = new Casino(); 
       businessName = _casino.GetBusinessName(); 
      } 
      else if (T == DrugStore) // Error: How can I check the type? 
      { 
       _drugStore = new DrugStore(); 
       businessName = _drugStore.GetBusinessName(); 
      } 

      return businessName; 

     } 
    } 

Solo quiero tener algo como esto en el cliente.

protected void Page_Load(object sender, EventArgs e) 
    { 
     var businessManager = new BusinessManager<Casino>(); 
     Response.Write(businessManager.ShowBusinessName()); 

     businessManager = new BusinessManager<DrugStore>(); 
     Response.Write(businessManager.ShowBusinessName()); 
    } 

Aviso que en realidad no ha creado el objeto real para el casino y Farmacia cuando llamo al BusinessManager, que sólo tiene que pasar como restricción de tipo genérico de la clase. Solo necesito saber exactamente qué tipo estoy pasando BusinessManager para saber exactamente el tipo para instanciar. Gracias ...

PD: no quiero crear BusinessManager específica separada para el casino y Farmacia ..

También puede comentar sobre el diseño .. gracias ..

ADICIONAL: y ¿y si Casino clase y DrugStore es una clase abstracta =)

Respuesta

9

que debe hacer

public class BusinessManager<T> where T : Business, new() 
... 

T _business = new T(); 
string businessName = _business.GetBusinessName(); 
return businessName; 
+0

hmm .. intentaré este enfoque ... – CSharpNoob

+0

Gracias chicos por todas sus respuestas! pero le di el CHECK al primero que propuso el enfoque más apropiado ... ¡gracias! – CSharpNoob

+0

hey, ¿y si hago una clase de abstracción en la clase Casino and DrugStore? ¿Existe alguna solución para esto? – CSharpNoob

12

puede escribir

if(typeof(T) == typeof(Casino)) 

pero realmente este tipo de lógica es un olor a código.

Aquí hay una forma de evitar esto:

public class BusinessManager<T> where T : Business, new() { 
    private readonly T business; 
    public BusinessManager() { 
     business = new T(); 
    } 
} 

pero personalmente prefiero

public class BusinessManager<T> where T : Business { 
    private readonly T business; 
    public BusinessManager(T business) { 
     this.business = business; 
    } 

    public string GetBusinessName() { 
     return this.business.GetBusinessName(); 
    } 
} 
+0

Sí, esto es C++ ish, ¿hay alguna otra forma de hacerlo? gracias – CSharpNoob

+0

@CSharpNoob: Por favor, mira mi edición. – jason

+0

gracias, funciona! :) – CSharpNoob

1

se puede hacer algo como esto:

if (typeof(T) == typeof(SomeType)) 
{ 
    // Same 
} 
2

No sé sobre # sintaxis de C, pero no es posible hacer:

public class BusinessManager<T> where T : Business, new() 
    { 
     private T _business; 

     public string ShowBusinessName() 
     { 
      string businessName; 
      _business = new T(); 
      return _business.GetBusinessName(); 
     } 
    } 
+0

¿hay kiboard en java? –

+0

Necesita agregar ', new()' después de ': Business' –

+0

@Albin Sunnanbo: Fixed. Aunque solo resalta el hecho de que no sé C#. –

1

definir una clase BusinessManager como bramido:

public class BusinessManager<T> where T : Business 
{ 
    Business biz; 
    public BusinessManager() 
    { 
     biz = new T(); 
    } 

    public string ShowBusinessName() 
    { 
     return biz.GetBusinessName(); 
    } 
} 

y utilizarlo como abajo:

var businessManager = new BusinessManager<Casino>(); 
    Response.Write(businessManager.ShowBusinessName()); 

    var anotherBusinessManager = new BusinessManager<DrugStore>(); 
    Response.Write(businessManager.ShowBusinessName()); 

La forma en que lo usa perderá la encapsulación

2

Como otros chicos ya han mostrado varias respuestas a su primera pregunta, me gustaría abordar la segunda: diseño.

1. Papel de BusinessManager

papel real de la clase BusinessManager en su ejemplo no es demasiado clara. Como esta clase es genérica y no debe preocuparse por el tipo real de T, no hace nada más que agregar otra capa innecesaria entre la clase Business y el resto del programa.

En otras palabras, sólo tiene que utilizar:

Business casino = new Casino(); 
Response.Write(casino.GetBusinessName()); 

Business drugStore = new DrugStore(); 
Response.Write(drugStore.GetBusinessName()); 

Envolver esto de otra clase genérica no le ayuda mucho. Por otro lado, si desea tener alguna funcionalidad común para todas estas clases, puede agregarla directamente a su clase abstracta o extraer una interfaz y crear métodos de extensión para esa interfaz.

2. Usando las propiedades de captadores

Lo segundo, el uso de una propiedad es más apropiado cuando se tiene un método de obtención sencilla. En otras palabras, se debe reemplazar GetBusinessName() método con una propiedad Name (también omite el "negocio" del nombre, ya que no es necesario:

public interface IBusiness 
{ 
    string Name { get; } 
} 

public abstract class Business : IBusiness 
{ 
    public abstract string Name { get; } 
} 

public class Casino : Business 
{ 
    public override string Name 
    { 
     get { return "Casino Corp"; } 
    } 
} 

public class DrugStore : Business 
{ 
    public override string Name 
    { 
     get { return "DrugStore business"; } 
    } 
} 

y luego se puede utilizar de esta manera:

IBusiness casino = new Casino(); 
Response.Write(casino.Name); 

IBusiness drugStore = new DrugStore(); 
Response.Write(drugStore.Name); 

Además, puede ver que he introducido una interfaz IBusiness. La razón para hacerlo es permitirle implementar esta interfaz de formas más diversas. En este momento, tratará de derivar todas sus clases de la clase abstracta Business , y tratar de extraer la mayor parte de la funcionalidad común en el clase abstracta (ese es el propósito de la clase).

Pero extraer una gran cantidad de funcionalidad común tiene un costo: siempre hay una posibilidad de que va a llegar a una necesidad de crear una clase que no se deriva deBusiness. Si está accediendo a todos estos métodos a través de la interfaz IBusiness, a otras partes de su programa no les importará si esa implementación se deriva de Business o no.

+0

es básicamente una clase Wrapper, (envuelve a Casino y DrugStore y expone sus métodos comunes) pero como dices, puedo poner los métodos comunes directamente a la clase base, gracias por la entrada. – CSharpNoob

1

En VB.net puede usar la pseudo función GetType en un parámetro de tipo genérico para obtener un objeto Type de reflexión. Yo diría que C# debería tener un equivalente. Si por algún motivo no puede usar algo así, puede crear una matriz de 0 elementos del tipo deseado y luego verificar el tipo de esa matriz. Eso probablemente sería más barato que crear instancias de un elemento del tipo desconocido.

2

Dado que GetBusinessName se aplica realmente al tipo y no a las instancias del tipo, puede considerar el uso de DescriptionAttribute (o su propio BusinessNameAttribute) en lugar de una propiedad anulada y hacer que su BusinessManager obtenga el nombre comercial del atributo.

[Description("Casino Corp")] 
public class Casino : Business 
{ 
} 

Ahora ya no es necesario crear una instancia de la empresa solo para obtener su nombre. Para obtener la descripción, use:

public string ShowBusinessName() 
    { 
     var attribute = Attribute.GetCustomAttribute(typeof(T), typeof(DescriptionAttribute)) as DescriptionAttribute; 
     if (attribute == null) 
      return "Unknown business"; 

     return attribute.Description; 
    } 
Cuestiones relacionadas