[英]Use of Generic Collection in Non-Generic Interface
I've spent quite a while today looking for a way to solve this but with no luck. 今天,我花了相当长的时间寻找解决该问题的方法,但是没有运气。 I have a generic class as follows:
我有如下通用类:
public class StagedEntity<T>: IStagedEntity where T : IStagedItem {
public Type EntityType {
get { return typeof( T ); }
}
public IList<T> StagedItems { get; set; }
}
in order that I can create a collection of StagedEntities of various arbitrary types, ie: 为了可以创建各种任意类型的StagedEntities的集合,即:
var stagedEntities = new List<IStagedEntity> {
new StagedEntity<StagedBrand> {
StagedItems = new List<StagedBrand> {
new StagedBrand {
Code = "Brand1"
},
new StagedBrand {
Code = "Brand2"
}
}
},
new StagedEntity<StagedModel> {
StagedItems = new List<StagedModel> {
new StagedModel {
Name = "Model1"
},
new StagedBrand {
Name = "Model2"
}
}
}
}
I then wish to iterate over each entity in stagedEntities
, and with each one I need to be able to access all of the property values of each item in its StagedItems
collection, something like: 然后,我希望遍历
stagedEntities
每个实体,并且对于每个实体,我需要能够访问其StagedItems
集合中每个项目的所有属性值,例如:
private void DoStuff( IStagedEntity stagedEntity ) {
var properties = stagedEntity.EntityType.GetProperties().ToList();
foreach ( var item in stagedEntity.StagedItems ) { <=== This line doesn't compile
foreach ( var property in properties ) {
// Do something with
// property.GetValue( item, null );
}
}
}
However the above code doesn't compile because the interface definition IStagedEntity
doesn't have IList<T> StagedItems
defined, I can't put this in the interface definition because the interface is non-generic and so doesn't know what T
is. 但是上面的代码无法编译,因为接口定义
IStagedEntity
没有定义IList<T> StagedItems
,我不能将其放在接口定义中,因为接口是非泛型的,所以不知道T
是什么。
I've tried various things such as making the interface generic ( IStagedEntity<T>
) and defining StagedEntities
as new List<IStagedEntity<IStagedItem>>
, and I can get this to compile by casting each instance of StagedEntity<T>
to IStagedEntity<IStagedItem>
, however this fails at runtime with: 我已经尝试了各种方法,例如使接口通用(
IStagedEntity<T>
)并将StagedEntities
定义为new List<IStagedEntity<IStagedItem>>
,并且可以通过将StagedEntity<T>
每个实例StagedEntity<T>
为IStagedEntity<IStagedItem>
,但是在运行时失败并显示:
Unable to cast object of type
'DataExport.StagedEntity`1[DataExport.StagedBrand]' to type
'DataExport.IStagedEntity`1[DataExport.IStagedItem]'.
Is there an obvious way around this that I'm missing? 有什么办法可以解决我所缺少的吗? Any help would be much appreciated.
任何帮助将非常感激。
EDIT: For completeness, the IStagedEntity
interface at present looks like this: 编辑:为了完整
IStagedEntity
,当前的IStagedEntity
接口看起来像这样:
public interface IStagedEntity {
Type EntityType { get; }
}
If you can change the method signature of DoStuff()
, I'd suggest to keep your interfaces and classes as they are and just change the argument like this: 如果可以更改
DoStuff()
的方法签名,建议您将接口和类保持不变,并像这样更改参数:
private void DoStuff<T>(StagedEntity<T> stagedEntity) // note the arg type
{
var properties = stagedEntity.EntityType.GetProperties().ToList();
foreach ( var item in stagedEntity.StagedItems ) {
foreach ( var property in properties ) {
// Do something with
// property.GetValue( item, null );
}
}
}
So you can call that method like: 因此,您可以像这样调用该方法:
private void foo()
{
StagedEntity<MyGenericType> entities = null; // ...
DoStuff(entities);
}
Using dynamic will get you the result that you are asking for. 使用动态将获得所需的结果。 I would on the other side consider the other suggested approaches since you do not know if all IStagedEntity will meet the StagedItems property
另一方面,我将考虑其他建议的方法,因为您不知道所有IStagedEntity是否都符合StagedItems属性
private static void DoStuff(IStagedEntity stagedEntity)
{
dynamic se = stagedEntity;
var properties = stagedEntity.EntityType.GetProperties().ToList();
foreach (var item in se.StagedItems)
{
foreach (var property in properties)
{
// Do something with
// property.GetValue( item, null );
}
}
}
I've managed to get this to work by making the IStagedEntity
interface generic so I can include IList<T> StagedItems
in it - which I tried previously, but crucially I've now also made the interface type parameter covariant ( <out T>
) which has solved the conversion issue I was getting before: 我设法通过使
IStagedEntity
接口通用来使它IStagedEntity
因此我可以在其中包括IList<T> StagedItems
我之前曾尝试过,但很关键的是,现在我还使接口类型参数为协变( <out T>
)已解决了我之前遇到的转换问题:
public interface IStagedEntity<out T> where T : IStagedItem {
Type EntityType { get; }
IList<T> StagedItems { get; }
}
Obviously I've also had to amend all references to IStagedEntity
to IStagedEntity<IStagedItem>
, and having done so the assignment (simplified below) now works without issue: 显然,我还必须
IStagedEntity
IStagedEntity<IStagedItem>
所有引用都修改为IStagedEntity<IStagedItem>
,并且这样分配(现在简化了)现在可以正常工作了:
var stagedEntities = new List<IStagedEntity<IStagedItem>> {
new StagedEntity<StagedBrand>(),
new StagedEntity<StagedModel>()
}
And with IList<T> StagedItems
now in the interface I can happily access this property in my consuming method. 现在,在接口中有了
IList<T> StagedItems
,我可以很高兴地在使用方法中访问此属性。
Thanks for your help everyone :o) 谢谢大家的帮助:o)
EDIT: It's possibly worth pointing out that adding the covariant out
as described above will cause the compiler to complain of 'invalid variance' if there is a generic property with a setter on the interface. 编辑:这可能是值得指出的是,加入协变
out
如上所述将导致编译器抱怨“无效的差异”,如果有与接口上的一个设置的通用属性。 Simply removing the setter will fix this (and of course you can still have setters on the concrete implementation). 只需删除设置器即可解决此问题(当然,您仍然可以在具体实现中使用设置器)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.