使用不同的兼容类型覆盖属性
我需要一个带有属性的基类,我可以使用相同的属性但不同(兼容)类型派生类。 基类可以是抽象的。
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
这是因为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; } } }