【问题标题】:Get common property using Generic Interfaces使用通用接口获取公共属性
【发布时间】:2013-03-19 08:38:38
【问题描述】:

对不起,我无法用语言真正解释我想要做什么,但是..

假设我有 secnario。

public class TestClass
{
}

public class TestClass1 : TestClass, TestInterface<ValueClass1>
{
    public ValueClass1 Property { get; set; }
}

public class TestClass2 : TestClass, TestInterface<ValueClass2>
{
    public ValueClass2 Property { get; set; }
}

public interface TestInterface<T> where T : ValueClass
{
    T Property { get; set; }
}

public class ValueClass
{
    public int Id { get; set; }
}

public class ValueClass2 : ValueClass
{
}

我需要从包含TestClass1TestClass2(以及更多)的List&lt;TestClass&gt; 列表中从Property 获取一个值,但我不知道如何遍历列表并设置Property 值。

所以这基本上就是我想要做的事情

List<TestClass> list = new List<TestClass>();

foreach (var item in list.OfType<????>())
{
    item.Property = PropertyManager.GetProperty(item.Property.Id);
}

编辑:

我有许多具有共同属性的类,但我需要该属性的实际 Type 而不是 base Type(由于序列化等其他因素),并且我需要能够遍历列表主基类并访问该属性。

就像我上面的例子一样,我只需要从Property 中获取Id 值。

目前每个班级都有自己的Property,我正在使用Reflection 来做我需要的事情,我只是在寻找更清洁的解决方案。

编辑:

这是我当前的实现

public class TestClass
{
}

public class TestClass1 : TestClass
{
    public ValueClass Property { get; set; }
}

public class TestClass2 : TestClass
{
    public ValueClass2 Property { get; set; }
}

public class ValueClass
{
    public int Id { get; set; }
}

public class ValueClass2 : ValueClass
{
}

并设置我必须使用反射的值

List<TestClass> list = new List<TestClass>();

foreach (var item in list.Where(x => x.GetType().GetProperty("Property") != null))
{
    var property = item.GetType().GetProperty("Property");
    property.SetValue(PropertyManager.GetProperty((property.GetValue(item) as ValueClass).Id));
}

PropertyManager 只是ValueClass 类型中的Dictionary

public static ValueClass GetProperty(int id)
{
    if (_properties.Containskey(id))
    {
       return _properties[id];
    }
    return null;
}

所以我需要一种方法来循环“TestClass”列表并填充具有ValueClassProperty 的任何派生类型。

目前我认为Reflection 是我唯一真正的选择。

【问题讨论】:

  • 为什么你需要OfType 列表已经是TestClass 类型,它暴露了Property?
  • @BobVale,抱歉,查看我的编辑,我错过了示例中的基类。
  • 在您的示例中,如果您尝试在 TypeClass2 类型的实例上将 ValueClass 类型的值设置为 Property 属性,您期望会发生什么。这将在运行时失败。

标签: c# generics interface casting


【解决方案1】:

这些类关系是一团糟,我保证你不会对这些继承和参数关系感到满意。你能详细说明你想做什么吗?

无论如何,您可以通过以下方式访问 PropertyId

 static void Main(string[] args)
    {
        List<TestClass> list = new List<TestClass>();

        foreach (TestClass item in list)
        {
            ValueClass x = item.Property;
            int y = item.Property.Id;
        }
    }

在这种情况下,最好首先避免使用 var,以了解变量的类型。

编辑
一个快速且不太脏的解决方案是使用 dynamic

dynamic d = o; // assign the items in your list to a dynamic variable
var somevar = d.Property;    // access any property you expect x to have.

编辑 干净的解决方案是:
1. 定义一个接口,在循环中包含您想要和需要的所有内容。
2. 将接口附加到应实现它的类型。

【讨论】:

  • 虽然我同意,但这确实是评论,而不是答案。
  • 你是对的,我正在研究答案,然后停在这一点上。
  • 对不起,我举了一个很差的例子关于我想做的事情,我已经更新了这个问题,我错过了整个班级,所以并不是所有的班级都有Property只有一些派生类,我只有一个基类列表
  • @thomas,您对使用dynamic 与我目前的Reflection 解决方案有何看法,dynamic 会更快/更安全还是几乎一样?
  • 方便,不易出错,性能好。当类关系变得过于复杂时,动态是新的逃避场景(在正常情况下也不应该如此)。 Jon Skeet 的“C# in Depth”在第 415f 页有更长的解释,我都从我的经验中订阅。总而言之:如果由于语言限制而无法实现良好的类型安全访问,但 dynamic 做到了,那么您将面临在纯托管代码中使用 dynamic 的情况。
【解决方案2】:

你可以试试:

public class TestClass
{
    public virtual ValueClass Property { get; set; }
}

public class TestClass1 : TestClass
{
    private ValueClass property = null;
    public override ValueClass Property
    {
        get
        {
            return property;
        }
        set
        {
            property = (ValueClass)value;
        }
    }
}

public class TestClass2 : TestClass
{
    private ValueClass2 property = null;
    public override ValueClass Property
    {
        get
        {
            return property;
        }
        set
        {
            property = (ValueClass2)value;
        }
    }
}

public class ValueClass
{
    public int Id { get; set; }
}

public class ValueClass2 : ValueClass
{
}

和:

foreach (var item in list)
        {
            item.Property = PropertyManager.GetProperty(item);
        }

【讨论】:

  • 感谢您的回答,但是,我并不热衷于将 Property 添加到基类中,而且 Property 必须属于它 Type 不是基类,这个是由于 xaml DataTemplatesXmlSerialization 兼容性(长篇大论)。
【解决方案3】:
public interface IHasProperty {
   ValueClass PropertyAsValueClass { get;set; }
}

public class TestClass<T> : IHasProperty where T : ValueClass
{
   public T Property {get;set;}

   public ValueClass PropertyAsValueClass {
     get { return this.Property; }
     set { this.Property = value as T; }
   }
}

public class TestClass1 : TestClass<ValueClass>
{
}

public class TestClass2 : TestClass<ValueClass2>
{
}

public class ValueClass
{
    public int Id { get; set; }
}

public class ValueClass2 : ValueClass
{
}

如果您愿意,可以进行额外检查...

然后

var list = new List<IHasProperty>();
foreach (var item in list)
{
    item.PropertyAsValueClass = PropertyManager.GetProperty(item.PropertyAsValueClass.Id);
}

【讨论】:

  • 嗨 Bob,感谢您的回答,但我不能只将属性添加到 TestClassTestClass 用于 1000 多个地方,我开始考虑我的反射解决方案是唯一的解决方案:(
  • @sa_ddam213 你能新建一个继承自testclass的中间类,并让TestClass1和TestClass2继承自那个吗?
  • 我也想过,但它搞砸了 xml 序列化,我希望在类级别解决这个问题,但看起来我只需要坚持使用反射解决方案,因为它工作正常目前,但我只是希望有一种更清洁的方法来做到这一点,谢谢你的回答:)
  • 在每个类中实现接口然后使用list.OfType&lt;IHasProperty&gt;()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-02
  • 2010-11-30
  • 2011-10-03
  • 1970-01-01
相关资源
最近更新 更多