2010-10-31 8 views
10

Come posso verificare/valutare l'esatto tipo di T senza oggetto per T. So che la mia domanda forse confuso, ma considerare questo ...Generics Come controllare l'esatto tipo di T, senza oggetto per 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; 

     } 
    } 

Voglio solo avere qualcosa di simile sul client.

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()); 
    } 

Avviso che io in realtà non ha ancora creato l'oggetto reale per il Casinò e Farmacia quando chiamo il BusinessManager, mi basta passare come tipo di vincolo generico della classe. Ho solo bisogno di sapere esattamente che tipo sto passando BusinessManager per sapere cosa esattamente il tipo di istanziare. Grazie ...

PS: Non voglio creare BusinessManager specifica separata per Casinò e Farmacia ..

Si può anche commentare il disegno .. grazie ..

COMPLEMENTARI: e cosa succede se Casino di classe e Farmacia è una classe astratta =)

risposta

9

si dovrebbe fare

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

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

hmm .. mal provate questo approccio .. – CSharpNoob

+0

Grazie ragazzi per tutte le vostre risposte! ma ho dato il CHECK al primo che ha proposto l'approccio più appropriato .. grazie! – CSharpNoob

+0

hey, e se classificassi Class Casino e DrugStore anche in una classe astratta, c'è una soluzione? – CSharpNoob

12

è possibile scrivere

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

ma in realtà questo tipo di logica è un odore di codice.

Ecco un modo intorno a questo:

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

ma personalmente preferirei

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ì, questo è C++ ish, c'è un altro modo per farlo? grazie – CSharpNoob

+0

@CSharpNoob: Vedi la mia modifica. – jason

+0

grazie funziona! :) – CSharpNoob

1

si può fare qualcosa di simile:

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

Non so su C# la sintassi, ma non è forse possibile fare:

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

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

è lì dove kiboard in java? –

+0

È necessario aggiungere ', new()' dopo ': Business' –

+0

@Albin Sunnanbo: risolto. Anche se sottolinea solo il fatto che non conosco C#. –

1

definire una classe BusinessManager come muggito:

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

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

e utilizzarlo come muggito:

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

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

Il modo in cui l'utente ha perso l'incapsulamento

2

Poiché altri ragazzi hanno già mostrato varie risposte alla tua prima domanda, vorrei affrontare la seconda: il design.

1. Ruolo del BusinessManager

ruolo effettivo della classe BusinessManager nel tuo esempio non è troppo chiaro. Poiché questa classe è generica e non dovrebbe riguardare il tipo effettivo di T, non fa altro che aggiungere un altro livello non necessario tra la classe Business e il resto del programma.

In altre parole, si può semplicemente utilizzare:

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

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

Wrapping questo in un altro classe generica non ti aiuta molto. D'altra parte, se si desidera disporre di alcune funzionalità comuni per tutte queste classi, è possibile aggiungerle direttamente alla classe astratta oppure estrarre un'interfaccia e creare metodi di estensione per tale interfaccia.

2. proprietà utilizzando per getter

Seconda cosa, utilizzando una proprietà è più appropriato quando si dispone di un semplice metodo getter. In altre parole, è necessario sostituire GetBusinessName() metodo con una proprietà Name (Ho anche omesso il "Business" dal nome perché non è necessario:

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"; } 
    } 
} 

e poi si può usare in questo modo:

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

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

Inoltre, è possibile vedere che ho introdotto un'interfaccia IBusiness. La ragione per farlo è consentire l'implementazione di questa interfaccia in modi più diversi. In questo momento, proverai a ricavare tutte le tue classi dalla classe astratta Business e prova ad estrarre la maggior parte delle funzionalità comuni in classe astratta (questo è lo scopo della classe).

Ma l'estrazione di un sacco di funzionalità comuni viene fornito con un costo: c'è sempre una possibilità che verrà con la necessità di creare una classe che non è derivato daBusiness. Se si accede a tutti questi metodi attraverso l'interfaccia IBusiness, le altre parti del programma non saranno interessate se tale implementazione è derivata da Business o meno.

+0

è fondamentalmente solo un Wrapper Class, (avvolge sia Casino che DrugStore ed espone i loro metodi comuni) ma come dici tu, posso mettere i metodi comuni direttamente alla classe base, grazie per l'input .. – CSharpNoob

1

In VB.net è possibile utilizzare la pseudo-funzione GetType su un parametro di tipo generico per ottenere un oggetto Tipo di riflessione. Direi che C# dovrebbe avere un equivalente. Se per qualsiasi motivo non è possibile utilizzare qualcosa del genere, è possibile creare una matrice di 0 elementi del tipo desiderato, quindi verificare il tipo di tale matrice. Probabilmente sarebbe più economico dell'istanziazione di un elemento del tipo sconosciuto.

2

Dal GetBusinessName realmente si applica al tipo e non le istanze del tipo, si potrebbe considerare l'utilizzo di DescriptionAttribute (o la propria BusinessNameAttribute) invece di una proprietà sovrascritto e hanno il BusinessManager ottenere il nome di affari dall'attributo.

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

Ora non è più necessario creare un'istanza dell'azienda solo per ottenere il suo nome. Per ottenere la descrizione, utilizzare:

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

     return attribute.Description; 
    } 
Problemi correlati