为什么我不能通过索引访问KeyedCollection项目?

时间:2013-01-15 20:47:22

标签: c# .net collections

我有这个代码(我希望它可以工作,但它失败了)..我真的不知道为什么。请帮忙

     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   键)          at KeyedCollectionTest.Program.Main(String [] args)in ... \ Program.cs:第25行          在System.AppDomain._nExecuteAssembly(Assembly assembly,String [] args)          在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()          在System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态)          在System.Threading.ThreadHelper.ThreadStart()InnerException:

为什么要尝试获取Key而不是索引?键明显很长而不是int。我确信之前我使用过KeyedCollection,它对长键和int索引工作得很好。

我尝试在ver 2,3,4,4,4.5中编译(使用VS2012)...

别搞定。

4 个答案:

答案 0 :(得分:7)

  

为什么要尝试获取Key而不是索引?密钥显然很长而不是int。

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)
    }
}

请参阅我的article on overloading了解更多有趣的规则。

答案 1 :(得分:0)

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);
        }
    }
}

迭代密钥的方法不会在这里解决问题,或者我错过了什么?

答案 2 :(得分:0)

您也可以使用:

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

“ElementAt”允许您检索指定索引处的元素。如果你的键是int类型,这很好用。

答案 3 :(得分:0)

如果您在int上键入了如何通过索引访问KeyedCollection项目,那么此页面确实会出现在搜索结果中,因此它可能会有用在这里回答你这样做:

myKeyedCollectionInstance.Items[index];

indexint的位置。 .ItemsIListprotected而存在public,因此为了使其在课外以及从中继承的类可用,您必须添加{ {1}}或internal访问者方法,如下所示:

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