C# 4.0 中字典元素的 getter

发布于 2024-12-28 19:45:08 字数 260 浏览 0 评论 0原文

我想实现一个字典,仅在访问它们时(而不是提前)动态创建自己的元素。为此,我想使用 getter 方法,但我根本找不到任何有关如何在字典元素上下文中声明 getter 的信息。

我确实了解如何向整个字典添加一个 getter(调用时必须返回一个字典),但我想要做的是实现一个 getter,当访问字典中的单个元素时调用该 getter,以便我可以创建该元素在飞行中。该 getter 必须接收用于请求的密钥作为参数,并且必须返回相应的值。

我在文档中没有找到该任务的任何语法。

I want to implement a dictionary that creates its own elements on the fly only when they are accessed (not in advance). To do that I would like to use a getter method, but I simply don't find any information how to declare a getter in the context of dictionary elements.

I do understand how to add a getter to the whole dictionary (which must return a dictionary when called), but what I want to do is implement a getter that is called when a single element in the dictionary is accessed so I can create that element on the fly. That getter must receive the key that is used for the request as a parameter and it must return the corresponding value.

I do not find any syntax for that task in the docs.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

も让我眼熟你 2025-01-04 19:45:08

您只需要在 Dictionary<,> 上重新实现索引器。

    public class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            if (!TryGetValue(key, out value))
            {
                value = Activator.CreateInstance<TValue>();
                Add(key, value);
            }
            return value;
        }
        set { base[key] = value; }
    } 
}

如果您需要更复杂的值实例化,则可以使用激活器函数

 public class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    readonly Func<TKey, TValue> _activator;

    public MyDictionary(Func<TKey, TValue> activator)
    {
        _activator = activator;
    }

    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            if (!TryGetValue(key, out value))
            {
                value = _activator(key);
                Add(key, value);
            }
            return value;
        }
        set { base[key] = value; }
    } 
}

用法:

static void Main(string[] args)
{
    var dict = new MyDictionary<int, string>(x => string.Format("Automatically created Value for key {0}", x));
    dict[1] = "Value for key 1";
    for (int i = 0; i < 3; i++)
    {
        Console.WriteLine(dict[i]);
    }
    Console.Read();
}

You just need to reimplement the indexer on Dictionary<,>

    public class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            if (!TryGetValue(key, out value))
            {
                value = Activator.CreateInstance<TValue>();
                Add(key, value);
            }
            return value;
        }
        set { base[key] = value; }
    } 
}

If you need a more sophisticated value instantiation, you can use an activator function

 public class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    readonly Func<TKey, TValue> _activator;

    public MyDictionary(Func<TKey, TValue> activator)
    {
        _activator = activator;
    }

    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            if (!TryGetValue(key, out value))
            {
                value = _activator(key);
                Add(key, value);
            }
            return value;
        }
        set { base[key] = value; }
    } 
}

Usage:

static void Main(string[] args)
{
    var dict = new MyDictionary<int, string>(x => string.Format("Automatically created Value for key {0}", x));
    dict[1] = "Value for key 1";
    for (int i = 0; i < 3; i++)
    {
        Console.WriteLine(dict[i]);
    }
    Console.Read();
}
千年*琉璃梦 2025-01-04 19:45:08

虽然 Kev 的答案是完全正确的,并且是在专业水平上给出的,但它仍然给我带来了困难(并启动了很多富有成效的学习 - 感谢 Kev!)。正如您所知,我是 C# 的学习者,有许多概念我仍然需要吸收。我想在这里添加我自己的问题的答案,以防其他人遇到同样的问题并且与我的理解水平相似。也许这会节省一些生命。

Kev 在他的回答中使用了泛型——这是 C#2 中引入的一个很棒的概念。为了简化答案,我想在没有泛型的情况下显示它,并添加大量注释,这些注释给出了我必须查找的所有概念的提示(并且部分不容易找到):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DictionaryElementsGetter_Test {

  // class inherits from Dictionary<int, string>
  public class MyDictionary : Dictionary<int, string> {
    // new: hide element of base class to redefine it in derived class.
    //      see http://msdn.microsoft.com/en-us/library/435f1dw2.aspx
    // string this[int key]: create an indexer
    //                       (actually: replace the indexer of base class, because of "new")
    //                       see http://msdn.microsoft.com/en-us/library/2549tw02.aspx
    new public string this[int key] {
      get {
        string value;
        // out: pass argument by reference instead of by value
        //      This is the standard definition of TryGetValue.
        //      Beside the bool result that indicates the existence of the key-value-pair,
        //      TryGetValue also returns the value itself into this reference parameter (if key is found).
        //      see http://msdn.microsoft.com/en-us/library/ee332485.aspx
        if( !TryGetValue( key, out value ) ) {
          value = "abc" + key + "def";
          Add( key, value );
          // just to see when the getter really did an Add():
          Console.Write( "ADDED!... " );
        }
        return value;
      }
      // base: access element of the base class Dictionary<int, string>
      //       see http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.100).aspx
      set { base[key] = value; }
    }
  }


  class Program {
    static void Main( string[] args ) {

      var dict = new MyDictionary();
      dict[1] = "EXTERNAL VALUE";

      for( int i = 0; i < 3; i++ ) {
        Console.WriteLine( i + ": " + dict[i] );
      }
      /* 
      Output:
        ADDED!... 0: abc0def
        1: EXTERNAL VALUE
        ADDED!... 2: abc2def
      */
      for( int i = 0; i < 3; i++ ) {
        Console.WriteLine( i + ": " + dict[i] );
      }
      /* 
      Output:
        0: abc0def
        1: EXTERNAL VALUE
        2: abc2def
      */

      Console.ReadKey();

    }
  }
}

While the answer of Kev is perfectly correct and given on a professional level it still gave me a hard time (and initiated a lot of fruitful learning - thanks Kev!). As you can tell I am a learner of C# and there are many concepts that I still have to assimilate. I want to add an answer to my own question here in case anybody else has the same problem and is on a similar level of understanding as me. Maybe this will save some livetime.

Kev used Generics in his answer - a great concept introduced with C#2. To simplify the answer I want to show it without Generics and with a lot of comments added that give hints to all concepts that I had to look up (and that were partially not easy to find):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DictionaryElementsGetter_Test {

  // class inherits from Dictionary<int, string>
  public class MyDictionary : Dictionary<int, string> {
    // new: hide element of base class to redefine it in derived class.
    //      see http://msdn.microsoft.com/en-us/library/435f1dw2.aspx
    // string this[int key]: create an indexer
    //                       (actually: replace the indexer of base class, because of "new")
    //                       see http://msdn.microsoft.com/en-us/library/2549tw02.aspx
    new public string this[int key] {
      get {
        string value;
        // out: pass argument by reference instead of by value
        //      This is the standard definition of TryGetValue.
        //      Beside the bool result that indicates the existence of the key-value-pair,
        //      TryGetValue also returns the value itself into this reference parameter (if key is found).
        //      see http://msdn.microsoft.com/en-us/library/ee332485.aspx
        if( !TryGetValue( key, out value ) ) {
          value = "abc" + key + "def";
          Add( key, value );
          // just to see when the getter really did an Add():
          Console.Write( "ADDED!... " );
        }
        return value;
      }
      // base: access element of the base class Dictionary<int, string>
      //       see http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.100).aspx
      set { base[key] = value; }
    }
  }


  class Program {
    static void Main( string[] args ) {

      var dict = new MyDictionary();
      dict[1] = "EXTERNAL VALUE";

      for( int i = 0; i < 3; i++ ) {
        Console.WriteLine( i + ": " + dict[i] );
      }
      /* 
      Output:
        ADDED!... 0: abc0def
        1: EXTERNAL VALUE
        ADDED!... 2: abc2def
      */
      for( int i = 0; i < 3; i++ ) {
        Console.WriteLine( i + ": " + dict[i] );
      }
      /* 
      Output:
        0: abc0def
        1: EXTERNAL VALUE
        2: abc2def
      */

      Console.ReadKey();

    }
  }
}
夜灵血窟げ 2025-01-04 19:45:08

它已经在框架中实现了。如果您致电,

Dictionary<int, string> _myDictionary = new Dictionary<int, string>();

_myDictionary[1] = "Hello";
_myDictionary[2] = "World!";

您的字典将填充键值对 <1,“Hello”>,<2,“World!”> 等。

It's already implemented in the framework. If you call

Dictionary<int, string> _myDictionary = new Dictionary<int, string>();

_myDictionary[1] = "Hello";
_myDictionary[2] = "World!";

you will have your dictionary populated with the key-value pairs <1, "Hello">, <2, "World!">

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文