我今天花了很长时间寻找解决方法,但没有运气。我有一个泛型类如下:
public class StagedEntity<T>: IStagedEntity where T : IStagedItem {
public Type EntityType {
get { return typeof( T ); }
}
public IList<T> StagedItems { get; set; }
}
为了能创建各种任意类型的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"
}
}
}
}
然后,我希望迭代stagedEntities
中的每个实体,并且每个实体都需要能够访问其StagedItems
集合中每个项目的所有属性值,例如:< / p>
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 );
}
}
}
但是上面的代码没有编译,因为接口定义IStagedEntity
没有定义IList<T> StagedItems
,我不能把它放在接口定义中,因为接口是非泛型的,所以不知道T
是什么。
我尝试了各种各样的事情,比如将接口设为通用(IStagedEntity<T>
)并将StagedEntities
定义为new List<IStagedEntity<IStagedItem>>
,我可以通过转换每个{{1}实例来编译它。 1}}到StagedEntity<T>
,但这在运行时失败:
IStagedEntity<IStagedItem>
有没有明显的方法可以解决这个问题?任何帮助将不胜感激。
编辑:为了完整性,目前Unable to cast object of type
'DataExport.StagedEntity`1[DataExport.StagedBrand]' to type
'DataExport.IStagedEntity`1[DataExport.IStagedItem]'.
界面如下所示:
IStagedEntity
答案 0 :(得分:0)
如果你可以改变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 );
}
}
}
所以你可以像下面这样调用这个方法:
private void foo()
{
StagedEntity<MyGenericType> entities = null; // ...
DoStuff(entities);
}
答案 1 :(得分:0)
使用动态将获得您要求的结果。我会在另一方面考虑其他建议的方法,因为您不知道所有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 );
}
}
}
答案 2 :(得分:0)
我设法通过将IStagedEntity
接口设为通用来实现此功能,因此我可以在其中包含IList<T> StagedItems
- 我之前尝试过,但至关重要的是我现在还制作了接口类型参数协变(<out T>
)解决了我之前遇到的转换问题:
public interface IStagedEntity<out T> where T : IStagedItem {
Type EntityType { get; }
IList<T> StagedItems { get; }
}
显然,我还必须修改IStagedEntity
到IStagedEntity<IStagedItem>
的所有引用,并且在完成此任务后(下面简化)现在可以正常运行:
var stagedEntities = new List<IStagedEntity<IStagedItem>> {
new StagedEntity<StagedBrand>(),
new StagedEntity<StagedModel>()
}
现在在界面中IList<T> StagedItems
,我可以愉快地在我的消费方法中访问此属性。
感谢大家的帮助:o)
编辑:可能值得指出的是,如果在接口上存在带有setter的泛型属性,则如上所述添加协变out
将导致编译器抱怨'无效方差'。简单地删除setter就可以解决这个问题(当然,你仍然可以在具体实现上设置setter)。