132

为什么在 C# 中不允许使用静态索引器?我认为没有理由不应该允许它们,而且它们可能非常有用。

例如:

public static class ConfigurationManager 
{
        public object this[string name]
        {
            get => ConfigurationManager.getProperty(name);
            set => ConfigurationManager.editProperty(name, value);
        }

        /// <summary>
        /// This will write the value to the property. Will overwrite if the property is already there
        /// </summary>
        /// <param name="name">Name of the property</param>
        /// <param name="value">Value to be wrote (calls ToString)</param>
        public static void editProperty(string name, object value) 
        {
            var ds = new DataSet();
            var configFile = new FileStream("./config.xml", FileMode.OpenOrCreate);
            ds.ReadXml(configFile);

            if (ds.Tables["config"] == null)
                ds.Tables.Add("config");

            var config = ds.Tables["config"];

            if (config.Rows[0] == null) 
                config.Rows.Add(config.NewRow());

            if (config.Columns[name] == null) 
                config.Columns.Add(name);

            config.Rows[0][name] = value.ToString();

            ds.WriteXml(configFile);
            configFile.Close();
        }

        public static void addProperty(string name, object value) =>
            ConfigurationManager.editProperty(name, value);

        public static object getProperty(string name) 
        {
            var ds = new DataSet();
            var configFile = new FileStream("./config.xml", FileMode.OpenOrCreate);
            ds.ReadXml(configFile);
            configFile.Close();

            if (ds.Tables["config"] == null) return null;

            var config = ds.Tables["config"];

            if (config.Rows[0] == null) return null;
            if (config.Columns[name] == null) return null;

            return config.Rows[0][name];
        }
    }

上面的代码将从静态索引器中受益匪浅。但是它不会编译,因为不允许使用静态索引器。为什么会这样?

4

7 回答 7

99

我相信它被认为不是非常有用。我认为这也是一种耻辱——我倾向于使用的一个例子是编码,Encoding.GetEncoding("foo")可能是Encoding["Foo"]. 我不认为它会经常出现,但除此之外,它只是感觉有点不一致,不可用。

我必须检查一下,但我怀疑它已经在 IL(中间语言)中可用。

于 2008-12-30T20:20:59.617 回答
76

索引器表示法需要引用this. 由于静态方法没有对类的任何特定实例的引用,因此您不能this与它们一起使用,因此您不能在静态方法上使用索引器表示法。

您的问题的解决方案是使用单例模式,如下所示:

public class Utilities
{
    private static ConfigurationManager _configurationManager = new ConfigurationManager();
    public static ConfigurationManager ConfigurationManager => _configurationManager;
}

public class ConfigurationManager
{
    public object this[string value]
    {
        get => new object();
        set => // set something
    }
}

现在您可以Utilities.ConfigurationManager["someKey"]使用索引器表示法进行调用。

于 2008-12-30T19:47:48.653 回答
9

作为一种解决方法,您可以在单例/静态对象上定义实例索引器(假设 ConfigurationManager 是单例,而不是静态类):

class ConfigurationManager
{
  //private constructor
  ConfigurationManager() {}
  //singleton instance
  public static ConfigurationManager singleton;
  //indexer
  object this[string name] { ... etc ... }
}
于 2008-12-30T19:42:16.933 回答
1

我也需要(好吧,更像是拥有)一个静态索引器来存储属性,所以我想出了一个有点尴尬的解决方法:

在您想要拥有静态索引器的类中(此处为:Element),创建一个同名的子类 +“Dict”。给它一个只读静态作为所述子类的实例,然后添加您想要的索引器。

最后,将类添加为静态导入(因此子类只公开静态字段)。

import static Element.ElementDict;

public class Element {
    // .... 
    private static readonly Dictionary<string, object> elemDict = new Dictionary<string, object>();
    public class ElementDict {
        public readonly static ElementDict element = new ElementDict();
        public object this[string key] {
            get => elemDict.TryGetValue(key, out object o) ? o : null;
            set => elemDict[key] = value;
        }
    }
}

然后您可以将其大写为 Type 或不用作字典:

var cnt = element["counter"] as int;
element["counter"] = cnt;

但是,唉,如果要实际使用对象作为“值”-Type,那么下面的内容会更短(至少作为声明),并且还提供即时类型转换:

public static T load<T>(string key) => elemDict.TryGetValue(key, out object o) ? (T) o : default(T);
public static void store<T>(string key, T value) => elemDict[key] = value;

var cnt = Element.load<int>("counter");
Element.store("counter", cnt);
于 2019-03-05T15:12:47.967 回答
0

使用 C# 6 中较新的构造,您可以使用属性表达式主体简化单例模式。例如,我使用了以下与 code-lense 配合得很好的快捷方式:

public static class Config
{
   public static NameValueCollection Get => ConfigurationManager.AppSettings;
}

它还有一个额外的好处,即可以查找替换以升级旧代码并统一您的应用程序设置访问。

于 2018-08-28T05:06:51.920 回答
-2

this 关键字引用类的当前实例。静态成员函数没有 this 指针。this 关键字可用于从构造函数、实例方法和实例访问器中访问成员。(从msdn检索)。由于 this 引用了类的实例,因此它与 static 的性质相冲突,因为 static 与类的实例无关。

一种解决方法如下,它允许您对私有字典使用索引器,因此您只需要创建一个新实例并访问静态部分。

    public class ConfigurationManager 
{
    public ConfigurationManager()
    {
        // TODO: Complete member initialization
    }
    public object this[string keyName]
    {
        get
        {
                return ConfigurationManagerItems[keyName];
        }
        set
        {
                ConfigurationManagerItems[keyName] = value;
        }
    }
    private static Dictionary<string, object> ConfigurationManagerItems = new Dictionary<string, object>();        
}

这允许您跳过整个访问类成员的过程,只需创建它的一个实例并为其编制索引。

    new ConfigurationManager()["ItemName"]
于 2013-10-27T07:22:58.483 回答
-3

原因是很难理解您使用静态索引器索引的确切内容。

您说代码会从静态索引器中受益,但真的会这样吗?它所要做的就是改变这一点:

ConfigurationManager.editProperty(name, value);
...
value = ConfigurationManager.getProperty(name)

进入这个:

ConfigurationManager[name] = value
...
value = ConfigurationManager[name]

这不会以任何方式使代码变得更好;它并不比许多代码行更小,由于自动完成,编写起来并不容易,而且不太清楚,因为它隐藏了你正在获取和设置你称之为“属性”的东西的事实,它实际上迫使读者阅读有关索引器返回或设置的确切内容的文档,因为它绝对不是您要为其编制索引的属性,而两者都有:

ConfigurationManager.editProperty(name, value);
...
value = ConfigurationManager.getProperty(name)

您可以大声朗读并立即了解代码的作用。

请记住,我们要编写易于(= 快速)理解的代码,而不是编写快速的代码。不要将编写代码的速度与完成项目的速度混淆。

于 2018-01-31T14:40:26.943 回答