2

假设我们有以下场景:一个派生自 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 显式声明为字符串而新索引器只是隐藏继承的索引器相同?

正如我所说,它非常直观,不会引发任何错误或警告,但我想知道它的工作机制,因为在我看来这是一个更复杂的成员隐藏版本。

4

1 回答 1

3

阴影

假设我们有这个基类

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属性!我们可以做的是告诉 C# 编译器,当我们使用时,DerivedClass我们想使用我们的Name属性。我们通过将new属性添加到Name属性中来做到这一点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 为 astring时),但当它需要时,它是隐式的new。因此,在这些情况下,C# 编译器将使用它所知道的方法/索引器的版本。

在将其用作 的情况下StringDictionary<string>,它将使用您的自定义实现。在将其用作 的情况下Dictionary<string, string>,它将使用Dictionary<string,string>索引器的实现。

于 2013-06-09T18:03:03.163 回答