2010-07-13 18 views
1

J'ai une classe générique DirectorySource<T> qui dépend d'une interface IDirectorySearch<T>.Contrainte constructeur sur les types génériques ou simplement vérifier la contrainte dans mon constructeur de type générique?

Les deux sont génériques et ont la même contrainte de type:

public class DirectorySource<T> where T : IDirectoryEntry { } 

public interface IDirectorySearcher<T> where T : IDirectoryEntry { } 

Ainsi, par exemple, quand je veux une source de manipuler des groupes, j'aller dans cette voie:

IDirectorySearcher<Group> groupSearcher = new GroupSearcher(ROOT, SCOPE); 
IDirectorySource<Group> groups = new DirectorySource(groupSearcher); 

Ce que je souhaite arriver à est de forcer, lorsque mon type générique DirectorySource<T> est de type DirectorySource<Group>, que mon chercheur est un GroupSearcher, et je ne veux pas un être en mesure de passer dans un UserSearcher, par exemple.

J'ai lu les articles suivants:

  1. C#: Generic types that have a constructor?;
  2. An Introduction to C# Generics;
  3. new Constraint (C# Reference).

Et je ne vois pas comment gérer ce genre de contrainte avec ma classe. Pour l'instant, je donne les résultats suivants:

public class DirectorySource<T> where T : IDirectoryEntry { 
    public DirectorySource(IDirectorySearcher<T> searcher) { 
     Searcher = searcher; 
    } 

    public IDirectorySearcher<T> Searcher { get; private set; } 
} 

Et puis, je les suivantes aussi:

public class GroupSearcher : IDirectorySearcher<Group> { 

    public GroupSearcher(DirectoryEntry root, SearchScope scope) { 
     NativeSearcher = new DirectorySearcher(); 
     NativeSearcher.SearchRoot = root; 
     NativeSearcher.SearchScope = scope; 
    } 

    // Implementing interface... 
} 

Je ne peux pas simplement remplacer le type de propriété Searcher, car cela causerait ma classe générique devenir non générique.

Une idée ou quelque chose que je n'ai pas compris correctement sur cette contrainte de constructeur sur la façon dont je devrais aller avec ce que je veux accomplir?

EDIT # 1

La raison pour laquelle je veux faire est que l'on peut faire ce qui suit:

IDirectorySearcher<User> userSearcher = new UserSearcher(ROOT, SCOPE); 
IDirectorySource<Group> groups = new DirectorySource<Group>(userSearcher); 

Cela me semble incorrect ...

1. Est-ce qu'il me manque quelque chose d'évident ici? =)

Merci d'avance!

+1

Que demandez-vous exactement? – SLaks

+0

@SLaks: Est-ce que cela devient plus clair avec mon ** EDIT # 1 **? Sinon, je m'efforcerai de le faire. –

Répondre

3

Ce que je veux venir avec est à la force, quand mon DirectorySource de type générique est de de type DirectorySource<Group>, que mon chercheur est un GroupSearcher.

Pourquoi? Cela va-t-il à l'encontre de l'encapsulation de la fonctionnalité de recherche dans une interface, sûrement?Vous ne devriez pas vous préoccuper de l'implémentation, tant qu'elle peut rechercher les bons types d'entrée.

Je ne pense pas que les contraintes du constructeur sont vraiment pertinentes ici - qui ne vous permettra de créer une nouvelle instance de T sans argument ...

EDIT: Je ne vois pas comment votre problème est proposé effectivement un problème. Regardons le code:

IDirectorySearcher<User> userSearcher = new UserSearcher(ROOT, SCOPE); 
IDirectorySource<Group> groups = new DirectorySource<Group>(userSearcher); 

Voici le T pour DirectorySource<T> est Group. Maintenant, le constructeur vous demandera de passer un IDirectorySearcher<Group> - ce que userSearcher n'est pas, pour autant que je puisse le voir. Donc, ce code ne compilera pas, ce que vous voulez. Où est le problème?

+0

Merci pour votre réponse. Pourquoi je veux le faire parce que, comme pour l'instant, on pourrait faire ce qui suit: (s'il vous plaît voir mon edit # 1). –

+0

Si vous voyez mon ** EDIT # 1 **, vous pouvez maintenant mieux comprendre pourquoi je veux forcer ou contrainte ou quoi que ce soit à un 'GroupSearcher', pour continuer avec mon exemple. –

+0

Que croyez-vous que je devrais faire à la place? Mon design est-il mauvais? = S –

2

Avez-vous envisagé:

public class DirectorySource<TValue, TSearcher> 
      where TValue : IDirectoryEntry 
      where TSearcher : IDirectorySearcher<T>, new() 
{ 
    public DirectorySource(TSearcher seacher) 
    { 
     Searcher = seacher 
    } 

    public TSearcher Searcher { get; private set; } 
} 

IDirectorySearcher<Group> groupSearcher = new GroupSearcher(ROOT, SCOPE);  
var groups = new DirectorySource<Group, GroupSearcher>(groupSearcher); 
+0

+1 Non, je n'en ai même pas un peu. –

+0

Je ne pense pas que ce soit nécessaire ... Je ne vois pas pourquoi ce serait. Voir ma modification. –

+0

Je l'ai fait aussi dans certaines situations où je pensais que c'était logique. J'avais l'impression que cette approche compilerait de telle sorte que tous les appels aux méthodes sur l'instance TSearcher seraient des appels directs aux méthodes du type réel au lieu des appels virtuels à travers l'interface. J'ai essayé cela et j'ai trouvé que ma compréhension n'était pas vraiment le cas (selon ILDASM). Ce n'est pas que la performance est généralement si importante pour moi que je me soucie de savoir si les appels sont virtuels ou non, mais au moins c'était un avantage que je pouvais penser pour cette approche. Est-ce que je manque quelque chose? –

1

Je pense que la seule façon que vous allez obtenir ce que vous voulez (si je comprends bien) est que si vous ajoutez une méthode GetSource-IDirectorySearcher qui renvoie une mise en œuvre de IDirectorySource<T> .

+0

+1 Pas une mauvaise idée.Pourtant, quand je veux appliquer les changements en attente, c'est le devoir de ma source, et non le chercheur. En d'autres termes, je voudrais que mon 'GroupSearcher' fasse partie de ma' DirectorySource', mais c'est un mauvais design quand je veux fusionner les deux. –