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

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

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 l = new List(); //... } } 

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

 public class BaseG { public T prop { get; set; } } public class UseIt { public void use() { List l = new List(); // requires type argument //... } } 

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

 public abstract class Base { public abstract void Use(); public abstract object GetProp(); } public abstract class GenericBase : Base { public T Prop { get; set; } public override object GetProp() { return Prop; } } public class StrBase : GenericBase { public override void Use() { Console.WriteLine("Using string: {0}", Prop); } } public class IntBase : GenericBase { public override void Use() { Console.WriteLine("Using int: {0}", Prop); } } 

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

样品用法:

 class Program { static void Main(string[] args) { List l = new List(); l.Add(new StrBase {Prop = "foo"}); l.Add(new IntBase {Prop = 42}); Console.WriteLine("Using each item"); foreach (var o in l) { o.Use(); } Console.WriteLine("Done"); Console.ReadKey(); } } 

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

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

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

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

 b.prop = 5; 

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

同样的原则适用于generics:

 List> l = new List>(); BaseG s = new BaseG(); // The compiler will not allow this. l.add(s); // Here's the same problem, convert integer to string? BaseG o = l[0]; o.prop = 5; 

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

解决方案

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

 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; } } }