Will Marcouiller
Will Marcouiller

Reputation: 24132

Constructor constraint on generic types or simply check for constraint within my generic type constructor?

I have a generic class DirectorySource<T> which depends on an interface IDirectorySearch<T>.

Both are generics and have the same type constraint:

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

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

So, for instance, when I want a source to manipulate groups, I would go this way:

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

What I wish to come up with is to force, when my generic type DirectorySource<T> is of DirectorySource<Group> type, that my searcher is a GroupSearcher, and I don't want one to be able to pass in a UserSearcher, for example.

I have read the following articles:

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

And I don't seem to get how to handle this kind of constraint with my class. As for now, I have the following:

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

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

And then, I have the following too:

public class GroupSearcher : IDirectorySearcher<Group> {

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

    // Implementing interface...
}

I can't just replace the Searcher property type, as this would cause my generic class to become non-generic.

Any idea or something I didn't understand correctly about this constructor constraint on how I should go with what I want to accomplish?

EDIT #1

The reason I want to do so is because one could do the following:

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

This seems incorrect to me...

1. Am I missing something obvious here? =)

Thanks in advance!

Upvotes: 1

Views: 619

Answers (3)

Jon Skeet
Jon Skeet

Reputation: 1500695

What I wish to come up with is to force, when my generic type DirectorySource is of DirectorySource<Group> type, that my searcher is a GroupSearcher.

Why? That's going against the point of encapsulating the searcher functionality into an interface, surely? You shouldn't care what the implementation is, so long as it can search for the right kinds of entry.

I don't think constructor constraints are really relevant here - that would only allow you to create a new instance of T with no arguments...

EDIT: I can't see how your proposed problem is actually a problem. Let's look at the code:

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

So here the T for DirectorySource<T> is Group. Now the constructor will require you to pass in an IDirectorySearcher<Group> - which userSearcher isn't, as far as I can see. So this code wouldn't compile, which is what you want. Where's the problem?

Upvotes: 3

Donnie
Donnie

Reputation: 46923

I think the only way you're going to get what you want (as I understand it) is if you add a GetSource method to IDirectorySearcher which returns an implementation of IDirectorySource<T>.

Upvotes: 1

James Curran
James Curran

Reputation: 103515

Have you considered:

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

Upvotes: 2

Related Questions