How to list all elements that implement a common interface?

I have two interfaces: generic and not generic, which have an inheritance hierarchy:

public interface IGenericRelation<TParent, TChild> : IRelation public interface IRelation 

The general option is implemented by several server control elements that are dynamically loaded, and I want to list a set of controls that implement this interface. I can do the following

  foreach (IRelation relationControl in this.uiPlhControls.Controls.OfType<IRelation) { ... } 

But what I really would like to do is ...

  foreach (IGenericRelation<,> relationControl in this.uiPlhControls.Controls.OfType<IGenericRelation<,>) { ... } 

and then you can use relationControl with the types that it provided, then I will have access to the strongly typed properties available in IGenericRelation. Unfortunately, this is not possible, as it seems that I cannot omit the type parameters.

Does anyone know a way to list controls that implement a common interface so that I cannot write multiple loops instead of one? Is reflection possible?

+4
collections generics reflection c #
source share
2 answers

This is not possible since IGenericRelation<T,F> is a completely different type from IGenericRelation<G,I> . If you need access to certain properties that are common to all IGenericRelation , then you need to either implement them at the IRelation level, or introduce a third interface between IRelation and IGenericRelation<,> that implements these. The reason for this is that the compiler there is no means to determine what types to expect from him.

The easiest way is to implement two of your properties as an object at a higher level (either IRelation or an intermediate interface) and strictly typed at the level of IGenericRelation<,> .

+3
source share

What strongly typed properties are you trying to get? If they are strongly typed because they are input types of common ones, then you cannot access them without supplying types in your foreach loop. If they are strongly typed but not related to the supplied types, can you transfer them to the IRelation class?

This will make more sense with the sample code - let's say your classes are something like:

 public IRelation { public string RelationshipType { get; set; } } public IGenericRelation<TParent, TChild> : IRelation { public TParent Parent { get; set; } public TChild Child { get; set; } } 

If your list contains one IGenericRelation<Foo, Bar> and one IGenericRelation<Fizz, Buzz> , you cannot list and return both without knowing what specific type you are looking for:

 //Theoretical, non-compiling example.... foreach (IGenericRelation<,> relationControl in this.uiPlhControls.Controls.OfType<IGenericRelation<,>>) { //This wouldn't work for type IGenericRelation<Fizz, Buzz> relationControl.Parent.FooProperty = "Wibble"; //You would be able to access this, but there is no advantage over using IRelation relationControl.RelationshipType = "Wibble"; } 

(Note that I also had to change the type of the Control relationship in foreach from your sample code, so the possible use makes sense.)


In principle, it may be useful to think that .NET generics are the same as templates with a C ++ template (I know that the implementation is different, but the effect is the same in this respect). Imagine that during compilation all your code is checked for the use of the IGenericRelation class, and specific, not general, classes are created by searching for the TParent and TChild keywords and replacing them with the requested type. Since the two classes created are just as separate as any other .NET classes, it makes no sense to query "all classes that started like this template", the best thing you can do is find a common base class or interface - in this case, IRelation.

+1
source share

All Articles