假设我们有以下场景:一个派生自 Dictionary 的类,并且该类也有一个字符串索引器的实现,但索引器返回值的属性不是键(可以将其视为字典)以 int 或 guid 作为键的元素,但也有一个您希望为其创建索引器的字符串属性)。
public class StringDictionary<TKey> :
Dictionary<TKey, object>
{
public object this[string val]
{ get { } set { } }
}
现在,这是 C# 的行为方式(相当直观),具体取决于实例化 StringDictionary 时 TKey 的类型
StringDictionary<string> dict1;
dict1["string"]; // will use the indexer defined in StringDictionary
StringDictionary<int> dict2;
dict2[0]; // will use the indexer defined in Dictionary
dict2["string"]; // will use the indexer defined in StringDictionary
- 如果 TKey 是字符串,则只有 StringDictionary 中声明的索引器可用
- 如果 TKey 不是字符串,则两个索引器都可用(StringDictionary 中的字符串索引器和 Dictionary 中的 TKey 索引器)
我的问题是:当通用基类中定义的索引器与派生类中定义的索引器之间存在“冲突”时(如上例所示),C# 如何决定使用哪个索引器?这是否与 TKey 显式声明为字符串并且新索引器只是隐藏继承的索引器相同?
正如我所说,它非常直观,它不会抛出任何错误或警告,但我想知道其工作原理,因为在我看来,这是成员隐藏的一个更棘手的版本。
最佳答案
阴影
假设我们有这个基类
public class BaseClass
{
public string Name { get; set; }
}
现在假设我们从它派生,并且出于某种原因,我们希望有一个行为不同的 name 属性:
public class DerivedClass
{
public string Name
{
get { return "Always the same"; }
set { throw new Exception(); }
}
}
C# 编译器会提示我们不能这样做,该类已经有 Name
属性(property)!我们能做的就是告诉 C# 编译器,当我们使用 DerivedClass
时我们想使用我们的Name
属性(property)。我们通过添加 new
来做到这一点属性(property)Name
属性(property) DerivedClass
:
public new string Name
这称为阴影
副作用
当您使用DerivedClass
时作为 DerivedClass
的类型一切都按照您的预期运行:
DerivedClass derived = new DerivedClass();
derived.Name = "Joe"; // Exception
但是如果您尝试使用Name
通过使用基类,您实际上正在使用 BaseClass
实现:
BaseClass base = derived;
base.Name = "Joe"; // No Exception
没有办法阻止这种情况。
回到问题
使用泛型时,不要将索引器标记为 new
因为它并不总是 new
方法(仅当 TKey 为 string
时才有效),但当需要时,它隐式为 new
。因此,在这些情况下,C# 编译器将使用它知道的方法/索引器的版本。
将其用作 StringDictionary<string>
的情况,它将使用您的自定义实现。将其用作 Dictionary<string, string>
的情况,它将使用 Dictionary<string,string>
索引器的实现。
关于c# - 索引器继承在泛型中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17011761/