2012-01-02 4 views
2

Je suis à la recherche d'une alternative C# aux typedefs C++ ou aux classes de traits dans un cas spécifique. Je sais qu'il n'y a pas d'équivalents directs, mais peut-être y a-t-il des solutions de rechange à ce problème précis?Type dérivé statiquement en C#?

Voici ce que j'essaie de faire. J'écris un cadre où il y a trois types liés. Une vue, un stockage de sauvegarde et une usine. Il y aura plusieurs implémentations des trois interfaces. Il existe une relation 1-1 entre la vue et l'usine et il existe une relation 1-N entre la vue et le stockage. Un impl implent. de la structure ressemble à ceci:

Storage : IStorage<int> ... 

View : IView<Storage> ... // And IView<T> : IViewNonGeneric further up.. 

Factory : IFactory<Storage> { 
    // This needs to take a concrete storage type as arg 
    IViewNonGeneric CreateView(Storage s) ... 

    Storage CreateStorage() ... 
} 

La classe View est la classe la plus importante pour les utilisateurs de la structure; les autres sont des détails de mise en œuvre. Pour cette raison, il semblerait plus naturel de définir l'usine en termes de classe View (et non en termes de stockage). En C++ ce serait simple, il suffit d'ajouter un typedef à la vue et l'utiliser dans l'usine, comme ceci:

class IView<typename T> { typedef T TStorage; ... 

class IFactory<typename T> { 
    IViewNonGeneric CreateView(typename T::TStorage s) ... 

en C# nous n'avons pas évidemment typedefs ou des classes de traits. Y a-t-il un autre moyen d'accomplir l'effet désiré? Autrement dit, peut-on utiliser View comme paramètre générique de Factory et dériver le type Source concret de la vue?

+1

ne suffit pas d'utiliser 'WHERE' dans la déclaration de génériques pour limiter le type doivent être mis en œuvre? – Tigran

Répondre

3

Les génériques en C# ne sont certainement pas aussi puissants que les modèles en C++. Cependant, C# a quelque chose de très puissant que C++ n'a pas: Reflection.

Il devrait être très facile de définir une méthode (statique ou instance) sur la classe d'affichage qui retournerait le type concret de classe de stockage. Vous pouvez ensuite utiliser Type.GetConstructor pour rechercher dynamiquement un constructeur de la classe de stockage et l'appeler à l'aide de la méthode ConstructorInfo.Invoke.

De plus, vous pouvez explorer l'utilisation des attributs personnalisés que vous pourriez affecter à votre classe d'affichage. Que diriez-vous quelque chose comme ceci:

[StorageType(typeof(MyStorage1) ] 
class MyView1 { ... } 

Utilisez ensuite la réflexion sur typeof (MyView1) pour voir si elle a StorageTypeAttribute associée.

+0

Merci pour votre suggestion. Cela pourrait être le plus proche, mais malheureusement, cela ne fonctionnera pas car il faudrait changer les signatures des fonctions d'usine. – 4ZM

+0

Vous ne savez pas exactement pourquoi vous devez changer les signatures de la fonction d'usine. Vous pourriez faire de l'usine une classe générique. Ou ... vous pouvez combiner la réflexion avec les attributs – DXM

+0

Dans l'interface IFactory j'ai: T CreateStorage() (où T: IStorage). Que serait le sig. de cette fonction si le paramètre générique de l'interface IFactory a été modifié pour représenter une vue au lieu du stockage? – 4ZM

0

Je pense est ce que vous voulez:

public interface IStorage<T> 
{ 
} 

public class IntStorage : IStorage<int> 
{ 
} 

public interface IFactory<S, T> where S : IStorage<T> 
{ 
    IView<S, T> CreateView(S storage); 
} 

public interface IViewNonGeneric 
{ 
} 
public interface IView<S, T> : IViewNonGeneric where S : IStorage<T> 
{ 
} 

public class IntView : IView<IntStorage, int> 
{ 
} 

public class IntFactory : IFactory<IntStorage, int> 
{ 
    public IntView CreateView(IntStorage storage) 
    { 
     // create the view 
    } 
    // private interface implementation 
    IView<IntStorage, int> IFactory<IntStorage, int>.CreateView(IntStorage storage) 
    { 
     return CreateView(storage); 
    } 
} 

... 
Questions connexes