如何枚举实现通用接口的所有项目?

时间:2022-02-17 07:50:20

I have two interfaces, a generic and a non-generic that have an inheritence hierarchy:

我有两个接口,一个泛型和一个非泛型,具有继承层次结构:

public interface IGenericRelation<TParent, TChild> : IRelation

public interface IRelation

The generic one is implemented by several server controls that are loaded dynamically and I wish to enumerate on the collection of controls that implement this interface. I can do the following

通用的是由几个动态加载的服务器控件实现的,我希望枚举实现此接口的控件集合。我可以做以下事情

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

But what I'd really like to be able to do is...

但我真正希望能做的是......

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

and then be able to use the relationControl with the types that it supplied as then I'd have access to the strongly-typed properties available on IGenericRelation. Unfortunately this isn't possible as it seems I can't omit the type parameters.

然后能够将relationControl与它提供的类型一起使用,然后我就可以访问IGenericRelation上可用的强类型属性。不幸的是,这是不可能的,因为我似乎无法省略类型参数。

Does anyone know a way to enumerate the controls that implement a generic interface to prevent me having to write several loops instead of one? Using reflection perhaps?

有没有人知道枚举实现通用接口的控件的方法,以防止我必须编写几个循环而不是一个循环?或许使用反射?

2 个解决方案

#1


This isn't possible, as IGenericRelation<T,F> is a completely distinct type from IGenericRelation<G,I>. If you need access to particular properties that are common to all IGenericRelation's, then you'll either need to implement them at the IRelation layer, or introduce a third interface between IRelation and IGenericRelation<,> that implements these. The reason for this is that the compiler has no means by which to infer what types to expect it to implement.

这是不可能的,因为IGenericRelation 是与IGenericRelation 完全不同的类型。如果您需要访问所有IGenericRelation共有的特定属性,那么您需要在IRelation层实现它们,或者在IRelation和实现这些的IGenericRelation <,>之间引入第三个接口。这样做的原因是编译器无法推断出要实现的类型。 ,i> ,f>

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

最简单的方法是将两个属性作为更高级别的对象(IRelation或中间接口)实现,并在IGenericRelation <,>级别强类型化。

#2


Which strongly typed properties are you trying to access? If they are strongly typed because they are the input types of the generic then you won't be able to access them without supplying the types in your foreach loop. If they are strongly typed, but not related to the supplied types, can you move them to the IRelation class?

您尝试访问哪些强类型属性?如果它们是强类型的,因为它们是泛型的输入类型,那么如果不在foreach循环中提供类型,您将无法访问它们。如果它们是强类型的,但与提供的类型无关,您可以将它们移动到IRelation类吗?

This will make more sense with a code sample - let's say that 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 contained one IGenericRelation<Foo, Bar> and one IGenericRelation<Fizz, Buzz> you can't enumerate and get both back without knowing which concrete type you are looking for:

如果您的列表包含一个IGenericRelation 和一个IGenericRelation ,则无法在不知道您要查找的具体类型的情况下枚举并获取两者: ,buzz> ,bar>

//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 relationControl in the foreach from your example code so the possible usage makes some sense.)

(请注意,我还必须从示例代码中更改foreach中的relationControl类型,以便可能的用法有所帮助。)


Fundamentally it can be helpful to think of .NET generics the same as C++ templated classes (I know the implementation is different, but the effect in this regard is the same). Imagine that at compile time all your code is inspected for uses of the IGenericRelation class and concrete, non-generic, classes are created by performing a find for the TParent and TChild keywords and replacing them with the requested type. Since the two created classes are as separate as any two other .NET classes it makes no sense to request "all classes which started out as this template", the best you can do is look for a shared base class or interface - in this case IRelation.

从根本上说,将.NET泛型与C ++模板类相同可能会有所帮助(我知道实现是不同的,但在这方面的效果是相同的)。想象一下,在编译时,将检查所有代码是否使用IGenericRelation类,并通过对TParent和TChild关键字执行查找并将其替换为请求的类型来创建具体的非泛型类。由于两个创建的类与任何其他两个.NET类是分开的,因此请求“所有以该模板开头的类”是没有意义的,您可以做的最好的事情是查找共享基类或接口 - 在这种情况下IRelation。

#1


This isn't possible, as IGenericRelation<T,F> is a completely distinct type from IGenericRelation<G,I>. If you need access to particular properties that are common to all IGenericRelation's, then you'll either need to implement them at the IRelation layer, or introduce a third interface between IRelation and IGenericRelation<,> that implements these. The reason for this is that the compiler has no means by which to infer what types to expect it to implement.

这是不可能的,因为IGenericRelation 是与IGenericRelation 完全不同的类型。如果您需要访问所有IGenericRelation共有的特定属性,那么您需要在IRelation层实现它们,或者在IRelation和实现这些的IGenericRelation <,>之间引入第三个接口。这样做的原因是编译器无法推断出要实现的类型。 ,i> ,f>

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

最简单的方法是将两个属性作为更高级别的对象(IRelation或中间接口)实现,并在IGenericRelation <,>级别强类型化。

#2


Which strongly typed properties are you trying to access? If they are strongly typed because they are the input types of the generic then you won't be able to access them without supplying the types in your foreach loop. If they are strongly typed, but not related to the supplied types, can you move them to the IRelation class?

您尝试访问哪些强类型属性?如果它们是强类型的,因为它们是泛型的输入类型,那么如果不在foreach循环中提供类型,您将无法访问它们。如果它们是强类型的,但与提供的类型无关,您可以将它们移动到IRelation类吗?

This will make more sense with a code sample - let's say that 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 contained one IGenericRelation<Foo, Bar> and one IGenericRelation<Fizz, Buzz> you can't enumerate and get both back without knowing which concrete type you are looking for:

如果您的列表包含一个IGenericRelation 和一个IGenericRelation ,则无法在不知道您要查找的具体类型的情况下枚举并获取两者: ,buzz> ,bar>

//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 relationControl in the foreach from your example code so the possible usage makes some sense.)

(请注意,我还必须从示例代码中更改foreach中的relationControl类型,以便可能的用法有所帮助。)


Fundamentally it can be helpful to think of .NET generics the same as C++ templated classes (I know the implementation is different, but the effect in this regard is the same). Imagine that at compile time all your code is inspected for uses of the IGenericRelation class and concrete, non-generic, classes are created by performing a find for the TParent and TChild keywords and replacing them with the requested type. Since the two created classes are as separate as any two other .NET classes it makes no sense to request "all classes which started out as this template", the best you can do is look for a shared base class or interface - in this case IRelation.

从根本上说,将.NET泛型与C ++模板类相同可能会有所帮助(我知道实现是不同的,但在这方面的效果是相同的)。想象一下,在编译时,将检查所有代码是否使用IGenericRelation类,并通过对TParent和TChild关键字执行查找并将其替换为请求的类型来创建具体的非泛型类。由于两个创建的类与任何其他两个.NET类是分开的,因此请求“所有以该模板开头的类”是没有意义的,您可以做的最好的事情是查找共享基类或接口 - 在这种情况下IRelation。