【问题标题】:C#: accessing Dictionary by using a partial classC#:使用分部类访问字典
【发布时间】:2022-01-01 05:13:48
【问题描述】:

我正在尝试通过使用部分类以下列方式访问字典。这样做的最终目的是公开这个字典并允许不同的方法直接读取/写入它。

FilenameABC.cs 有这个代码,到目前为止对我来说似乎没问题:

namespace Namespace1
{
    partial class ClassA
    {
        public class ExampleDictionary
        {
            private Dictionary<int, string> _dict;

            public ExampleDictionary()
            {
                _dict = new Dictionary<int, string>();
            }
        }
    }
}

FilenameDEF.cs 有这个代码,这就是我遇到困难的地方。我不确定为什么 .Add 方法不起作用。在第一个中,我试图在创建 ExampleDictionary 类的实例之后使用它,这似乎很违反直觉(当然,鉴于我目前的知识水平)。在第二个中,我尝试从方法内部添加元素,即

namespace Namespace1
{
    partial class ClassA
    {
        ExampleDictionary instanceOfDict = new ExampleDictionary();
        instanceOfDict.Add(1, "Test1"); // This does not work

        public static void FunctionA()
        {            
            for (int i = 0; i < 10; i++)
            {
            string text = $"Test{i}";
            instanceOfDict.Add(i, text); // This does not work as well              
            }          
        }
    }
}

有人可以帮忙吗?

【问题讨论】:

  • 您需要继承Dictionary 或公开方法,但您为什么要这样做?看来您甚至根本不需要 ExampleDictionary 类。
  • 首先,没有Partial Class这样的东西。 partial 关键字只是表明一个类可以在多个文件中定义。类的定义规则保持不变,只是一些类成员可以定义在一个文件中,而其他部分可以定义在其他文件中。但是,定义规则保持不变。特别是,只有类成员可以定义在顶级,即直接在class MyClass { /* stuff */ } 级别内。您的代码:instanceOfDict.Add(1, "Test1"); 是一个函数调用,它不能存在于类的顶层
  • 我刚刚注意到第二个不起作用。这是对问题的糟糕描述 - 您有完整的错误消息,请与我们分享。你得到一个编译器错误吗?我猜第一个错误描述了我在第一条评论中所说的内容。第二个错误可能是因为静态方法无法访问实例成员。最后,解释一下您要做什么会很有用。
  • 嗨@zaggler。这样做的最终目的是“公开”字典并允许不同的方法直接读取/写入它。也许我缺少的是这种“曝光”本身,但我不知道该怎么做。
  • 你好@Flydog57。感谢您的帮助。当涉及到第二个“错误”时,没有编译错误。在编写代码时,我只是没有将 '.Add' 视为一种方法。我看到“Equals”、“GetHashCode”、“GetType”和“ToString”。一旦这被声明为字典,我不明白为什么我看不到字典方法。正如您所说,我很确定问题是“静态方法无法访问实例成员”,但我不确定我应该怎么做。这样做的最终目的只是公开这个字典并允许不同的方法直接读取/写入它。

标签: c# dictionary properties getter-setter partial-classes


【解决方案1】:

我仍然无法完全确定您要做什么。但我会尽力向您展示一些东西。

我正在使用你写的这句话:“这样做的最终目的是公开这个字典并允许不同的方法直接读取/写入它。”作为我的指南 p>

部分类问题

正如我在 cmets 中提到的:没有 Partial Class 这样的东西。 partial 关键字只是表明一个类可以在多个文件中定义。类的定义规则保持不变,只是类的一些成员可以定义在一个文件中,而其他部分可以定义在其他文件中。

您在此处遇到的问题与partial 关键字无关

你的两个//这不起作用备注

第一个看起来像这样:

partial class ClassA
{
    ExampleDictionary instanceOfDict = new ExampleDictionary();
    instanceOfDict.Add(1, "Test1"); // This does not work
    //other code
}

第一行声明了名为instanceOfDictClassA 的私有成员字段并对其进行了初始化。这就是它编译的原因。

第二行尝试将可运行代码(函数调用)直接放在类的顶级作用域中。你不能那样做。你可以把一堆东西放在一个类的顶级范围内(例如,字段、属性、方法、委托、枚举、内部类),但你不能把代码放在那里。

您的第二个问题如下所示:

public static void FunctionA()
{            
    for (int i = 0; i < 10; i++)
    {
        string text = $"Test{i}";
        instanceOfDict.Add(i, text); // This does not work as well              
    }          
}

FunctionA 是一个static 方法。 instanceOfDict 是类的私有字段,未声明为静态。您不能从静态方法将实例引用到实例级成员(方法、属性、字段...)。阅读 static 关键字。

创建一个有选择地公开字典的类

由于您想在类内部做一些字典工作,但将其暴露给外部,所以我全力以赴,在 &lt;TKey, TValue&gt; 上使我的类通用,以便它可以与任何类型的字典一起使用。

我还让它实现了Collection Initialization Pattern,这样你就可以像字典一样初始化你的类的实例。

要使用集合初始化模式,你的类必须做的事情:

  1. 实现 IEnumerableIEnumerable&lt;T&gt;T 可以是任何类型,而不仅仅是您正在收集的类型 - 如果您不在乎,甚至可以直接抛出 NotImplementedException

  2. 包括一个类似于public void Add (SomeType atLeastOneParameter) 的方法。如果需要,您可以拥有多个 Add 的重载。

所以,我从这个开始(注意它实现了IEnumerable&lt;T&gt;

public partial class TestExposedDictionary<TKey, TValue> : IEnumerable<TValue>
{
    private readonly Dictionary<TKey, TValue> _theDictionary = new Dictionary<TKey, TValue>();

    public void Add(TKey key, TValue value)
    {
        _theDictionary.Add(key, value);
    }

    public IEnumerator<TValue> GetEnumerator()
    {
        foreach (var kvp in _theDictionary)
        {
            yield return kvp.Value;
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

这足以让一个类看起来像一个字典(你可能想要添加一些方法来获取数据等。但是,这取决于你(你可能想要一个索引器(在TKey)和一个TryGetValue

但是,让我们为类添加更多随机功能(将其放在类的顶级范围内):

    public int Count => _theDictionary.Count;

    public IEnumerable<KeyValuePair<TKey, TValue>> GetKeyValuePairs()
    {
        foreach (var kvp in _theDictionary)
        {
            yield return kvp;
        }
    }

这将允许您查看字典中有多少内容,并允许您遍历字典收集的项目(KeyValuePairs)。随意添加更多功能。

最后,测试一下……

public static void Test()
{
    var testDict = new TestExposedDictionary<int, string> {
        {1, "one" },
        {5, "five" },
        {8, "eight" },
        {10, "ten" },
        {105, "hundredFive" },
    };

    // I can call Add in the normal way as well:
    testDict.Add(300, "threeHundred");

    Console.WriteLine($"TestDict Count: {testDict.Count}");
    foreach (string s in testDict)
    {
        Console.WriteLine(s);
    }
}

当我运行这段代码时,我得到:

TestDict Count: 6
one
five
eight
ten
hundredFive
threeHundred

使用部分分割

我不知道你为什么要使用partial class。通常这样做是为了让两块代码由不同的角色编辑/维护(典型的原因是 Visual Studio 的模板/向导机制维护partial class 的一侧和程序员的另一侧。

规则非常简单,您只需在两个文件中声明public partial class MyClass。这两个文件必须在同一个项目中(即编译到同一个 Assembly 中)并且类必须在同一个命名空间中。完成此操作后,只需将(顶级范围)的部分和部分拆分为两个 partial class 声明。

在这种情况下,我可能会这样拆分:

  • 一方面,我将实现声明的IEnumerator&lt;TValue&gt; 所需的两个函数:
    • public IEnumerator&lt;TValue&gt; GetEnumerator()
    • IEnumerator IEnumerable.GetEnumerator()
  • 另一边,我会放其他所有东西:
    • 字典声明和初始化
    • 另一个枚举器:public IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt; GetKeyValuePairs()
    • public int Count =&gt; _theDictionary.Count;
    • public void Add(TKey key, TValue value)

【讨论】:

  • 对此我无法表达我的感激之情。这也帮助我打破了我的一些误解。有时学习编程会让人感到沮丧,但幸运的是,有像你这样了不起的人,他们会用一天的时间来帮助别人。再次感谢!
  • 是的,我愿意。幸运的是,我刚刚获得了这个徽章,让我作为一个新手开始交易这种货币。 :-)
【解决方案2】:

静态方法FunctionA无法访问ClassA的实例成员。

要么将FunctionA 更改为非静态,要么将字典字段设为静态。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    • 2021-11-02
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 2012-12-27
    相关资源
    最近更新 更多