使用不同的兼容类型覆盖属性
Posted
技术标签:
【中文标题】使用不同的兼容类型覆盖属性【英文标题】:Override Property with different compatible Type 【发布时间】:2011-03-09 15:39:25 【问题描述】:我需要一个具有属性的基类,我可以在其中派生具有相同属性但不同(兼容)类型的类。基类可以是抽象的。
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>();
//...
我尝试使用泛型,但在使用该类时给我带来了问题,因为我想在列表中存储不同类型的基类。
public class BaseG<T>
public T prop get; set;
public class UseIt
public void use()
List<BaseG> l = new List<BaseG>(); // requires type argument
//...
【问题讨论】:
【参考方案1】:这是建议解决方案的另一种方法:
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);
基本上,我在中间添加了一个通用类,用于存储您正确键入的属性。假设您永远不需要从迭代List<Base>
成员的代码中访问Prop
,这将起作用。 (如果需要,您始终可以向 Base
添加一个名为 GetProp
的抽象方法,将泛型转换为对象。)
示例用法:
class Program
static void Main(string[] args)
List<Base> l = new List<Base>();
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() 方法来说明如何从基类直接访问属性。
【讨论】:
+1:这是对手头问题的干净解决方案。将基类与泛型部分分开。【参考方案2】:您不能覆盖属性的类型。看看下面的代码:
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;
【讨论】:
第一个解决方案的简单性很有吸引力。但是,如果“prop”被设置为不同的 Type 值会发生什么? 10 年后你会如何看待这个问题?阳光下的任何新鲜事物;) @BernoulliIT,我可能会重新考虑整体设计,因为我真的不需要这个;)根据我的经验,当读取允许不同的数据结构时,往往会出现这样的代码值类型,例如 JSON。通常最好将属性键入为object
,并意识到您有时正在处理最好不键入的数据结构。试图把它硬塞进类型系统不会让它变得更好,只会更复杂。
你将如何使用协变/逆变方法解决 OP 的问题?【参考方案3】:
这是可能的,因为 C# 9.0
从 C# 9.0 开始,覆盖方法支持协变返回类型。
(见Microsoft docs)
【讨论】:
【参考方案4】: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";
【讨论】:
以上是关于使用不同的兼容类型覆盖属性的主要内容,如果未能解决你的问题,请参考以下文章