使用不同的兼容类型覆盖属性

时间:2010-06-29 13:52:46

标签: c# generics inheritance properties .net-2.0

我需要一个带有属性的基类,我可以使用相同的属性但不同(兼容)类型派生类。基类可以是抽象的。

public class Base
{
    public virtual object prop { get; set; }
}

public class StrBase : Base
{
    public override string prop { get; set; } // compiler error
}

public class UseIt
{
    public void use()
    {
        List<Base> l = new List<Base>();
        //...
    }
}

我尝试使用Generics,但这在使用该类时给我一个问题,因为我想在List中存储不同类型的基类。

public class BaseG<T>
{
    public T prop { get; set; }
}

public class UseIt
{
    public void use()
    {
        List<BaseG> l = new List<BaseG>(); // requires type argument
        //...
    }
}

4 个答案:

答案 0 :(得分:26)

这是建议解决方案的另一种方法:

public abstract class Base
{
    public abstract void Use();
    public abstract object GetProp();
}

public abstract class GenericBase<T> : Base
{
    public T Prop { get; set; }

    public override object GetProp()
    {
        return Prop;
    }
}

public class StrBase : GenericBase<string>
{
    public override void Use()
    {
        Console.WriteLine("Using string: {0}", Prop);
    }
}

public class IntBase : GenericBase<int>
{
    public override void Use()
    {
        Console.WriteLine("Using int: {0}", Prop);
    }
}

基本上我在中间添加了一个通用类,用于存储正确类型的属性。假设您永远不需要从迭代Prop成员的代码中访问List<Base>,这将有效。 (您可以随时向名为Base的{​​{1}}添加一个抽象方法,如果需要,可以将泛型强制转换为对象。)

样本用法:

GetProp

编辑:添加了GetProp()方法,以说明如何从基类直接访问该属性。

答案 1 :(得分:6)

您无法覆盖属性的类型。看看下面的代码:

StrBase s = new StrBase();
Base b = s;

这是完全有效的代码。但是当你尝试这样做时会发生什么?

b.prop = 5;

整数可以转换为object,因为所有内容都来自object。但由于b实际上是一个StrBase实例,它必须以某种方式将整数转换为字符串,但它不能。这就是为什么不允许覆盖类型的原因。

同样的原则适用于泛型:

List<BaseG<object>> l = new List<BaseG<object>>();
BaseG<string> s = new BaseG<string>();

// The compiler will not allow this.
l.add(s);

// Here's the same problem, convert integer to string?
BaseG<object> o = l[0];
o.prop = 5;

这是因为C#2.0中的泛型类型是不变的。 C#4.0确实允许这种类型的转换,称为协方差和逆变。

<强>解决方案

一个选项是在需要时将object强制转换为字符串。您可以在子类中添加类型验证:

public class StrBase : Base
{
  private string propValue;

  public override object prop {
    get
    {
      return this.propValue;
    }
    set
    {
      if (value is string)
      {
        this.propValue = (string)value;
      }
    }
  }
}

您还可以在子类中公开类型安全的属性:

public class StrBase : Base
{
  public string strProp {
    get
    {
      return (string)this.prop;
    }
    set
    {
      this.prop = value;
    }
  }
}

答案 2 :(得分:1)

我也面临着这个问题,但是我找到了一种无需泛型类型的优雅方法。

我已经在此处撰写了有关此主题的完整文章:  http://materiagame.com/2019/09/04/override-property-type-in-a-derived-class

TheUncas21

答案 3 :(得分:0)

public class first
        {
            private int someV;

            public virtual object SomeV { get => someV; set => someV = (int)value; }

            public first() { }
        }

        public class two : first
        {
            private string someV;

            public override object SomeV { get => someV; set => someV = value.ToString(); }

            public two() { }
        }

及其使用:

first firstClass = new first();
firstClass.SomeV = 1;

two twoClass = new two();
twoClass.SomeV = "abcd";