为什么我不能按索引访问KeyedCollection项

本文关键字:KeyedCollection 访问 索引 不能按 为什么 | 更新日期: 2023-09-27 17:53:52

我有这段代码(我希望它能工作,但它失败了(。。我真的不知道为什么。请帮助

     static void Main(string[] args)
    {
        var x = new MyKeyedCollection();
        x.Add(new MyType() { Key = 400L, Value = 0.1 });
        x.Add(new MyType() { Key = 200L, Value = 0.1 });
        x.Add(new MyType() { Key = 100L, Value = 0.1 });
        x.Add(new MyType() { Key = 300L, Value = 0.1 });
        //foreach (var item in x)
        for (int i = 0; i < x.Count; i++)
        {
            //Debug.WriteLine(item.PriceLevel);
            Debug.WriteLine(x[i].Key);
        }
    }
}
public class MyType 
{
    public long Key;
    public double Value;
}
public class MyKeyedCollection : KeyedCollection<long, MyType>
{
    protected override long GetKeyForItem(MyType item)
    {
        return item.Key;
    }
}

例外:

System.Collections.Generic.KeyNotFoundException未处理
消息=字典中不存在给定的关键字
Source=mscorlib StackTrace:位于System.ThrowHelper.ThrowKeyNotFoundException((位于System.Collections.Generic.Dictionary 2.get_Item(TKey key) at System.Collections.ObjectModel.KeyedCollection 2.get_Item(TKey键(位于中的KeyedCollectionTest.Program.Main(String[]args(。。。''程序.cs:line 25位于System.AppDomain_nExecuteAssembly(程序集程序集,String[]args(位于Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly((在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态(在System.Threading.ThreadHelper.ThreadStart((内部异常:

为什么它试图获取Key而不是索引?键显然是长的,而不是int。我确信我以前使用过KeyedCollection,它对长键和int索引都很好。

我尝试在版本2、3.5、4、4.5中进行编译(使用VS2012(。。。

不明白。

为什么我不能按索引访问KeyedCollection项

为什么它试图获取Key而不是索引?密钥显然很长,而不是整数。

但是int可以转换为long,所以它是一个有效的候选成员。

问题是this[TKey key]索引器最初在KeyedCollection中声明,而this[int index]索引器最初是在Collection中声明的。重载解析规则指定首先搜索派生类最多的类,并且只有首先在该类型中声明的成员才被视为以开头。只有当搜索失败时,编译器才会向上移动到类型层次结构中的下一级。

所以如果你写:

Collection<MyType> collection = x;
for (int i = 0; i < x.Count; i++)
{
    Debug.WriteLine(collection[i].Key);
}

它会起作用,因为collection的编译时类型只是Collection<T>只有具有"int index"索引器。

这里有一个例子,它显示了相同的行为,而不使用泛型、索引器或抽象类:

using System;
class Base
{
    public void Foo(int x)
    {
        Console.WriteLine("Base.Foo(int)");
    }
}
class Derived : Base
{
    public void Foo(long y)
    {
        Console.WriteLine("Derived.Foo(long)");
    }
}
class Program
{
    static void Main()
    {
        Derived x = new Derived();
        Base y = x;
        x.Foo(5); // Derived.Foo(long)
        y.Foo(5); // Base.Foo(int)
    }
}

请参阅我关于重载的文章,了解更多有趣的规则。

class Program
{
    static void Main(string[] args)
    {
        var x = new MyKeyedCollection();
        x.Add(new MyType() { Key = 110L, Value = 0.1 });
        x.Add(new MyType() { Key = 122L, Value = 0.1 });
        x.Add(new MyType() { Key = 233L, Value = 0.1 });
        x.Add(new MyType() { Key = 344L, Value = 0.1 });
        foreach(int key in x.Keys())
        {   
            Console.WriteLine(x[key].Key);
        }
        Console.Read();
    }
}
public class MyType
{
    public long Key;
    public double Value;
}
public class MyKeyedCollection : KeyedCollection<long, MyType>
{
    protected override long GetKeyForItem(MyType item)
    {
        return item.Key;
    }
    public IEnumerable<long> Keys()
    {
        foreach (MyType item in this.Items)
        {
            yield return GetKeyForItem(item);
        }
    }
}

迭代键的方法不会解决这里的问题吗,或者我遗漏了什么?

您也可以简单地使用:

Debug.WriteLine(x.ElementAt(i).Key);

"ElementAt"允许您检索指定索引处的元素。如果您的密钥类型为int.

p>如果试图找出如果您在int上键入了KeyedCollection项,则如何通过索引访问该项,则该页面确实会出现在搜索结果中,因此在此处回答可能很有用。你这样做:
myKeyedCollectionInstance.Items[index];

其中,indexint.Items之所以存在,是因为IList,并且是protected,所以要使其在类和从其继承的类之外可用,您必须添加一个publicinternal访问器方法,如下所示:

internal new IList<Occupation> AllItems
{
    get { return this.Items; }
}