C# 静态索引器?

C# 静态索引器?,c#,.net,static,indexer,static-indexers,C#,.net,Static,Indexer,Static Indexers,为什么C#中不允许使用静态索引器?我认为没有理由不允许它们,而且它们可能非常有用 例如: public static class ConfigurationManager { public object this[string name] { get => ConfigurationManager.getProperty(name); set => ConfigurationManager.editPr

为什么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];
        }
    }
公共静态类配置管理器
{
公共对象[字符串名称]
{
get=>ConfigurationManager.getProperty(名称);
set=>ConfigurationManager.editProperty(名称、值);
}
/// 
///这将向属性写入值。如果属性已存在,则将覆盖该值
/// 
///物业名称
///要写入的值(调用字符串)
公共静态void editProperty(字符串名称、对象值)
{
var ds=新数据集();
var configFile=new FileStream(“./config.xml”,FileMode.OpenOrCreate);
ReadXml(configFile);
if(ds.Tables[“config”]==null)
添加(“配置”);
var config=ds.Tables[“config”];
if(config.Rows[0]==null)
config.Rows.Add(config.NewRow());
if(config.Columns[name]==null)
config.Columns.Add(名称);
config.Rows[0][name]=value.ToString();
ds.WriteXml(配置文件);
configFile.Close();
}
公共静态void addProperty(字符串名称、对象值)=>
ConfigurationManager.editProperty(名称、值);
公共静态对象getProperty(字符串名称)
{
var ds=新数据集();
var configFile=new FileStream(“./config.xml”,FileMode.OpenOrCreate);
ReadXml(configFile);
configFile.Close();
if(ds.Tables[“config”]==null)返回null;
var config=ds.Tables[“config”];
if(config.Rows[0]==null)返回null;
if(config.Columns[name]==null)返回null;
返回config.Rows[0][name];
}
}

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

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


索引器符号要求引用此。由于静态方法没有对类的任何特定实例的引用,因此不能对它们使用
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
    }
}

现在,您可以使用索引器符号调用
实用程序.ConfigurationManager[“someKey”]

我认为它没有太大用处。我认为这也是一种耻辱——我倾向于使用的一个例子是编码,其中
Encoding.GetEncoding(“foo”)
可以是
Encoding[“foo”]
。我不认为它会经常出现,但除了其他任何事情,它只是觉得有点不一致,无法提供


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

this关键字指的是类的当前实例。静态成员函数没有this指针。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>();        
}

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

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

ConfigurationManager.editProperty(name, value);
...
value = ConfigurationManager.getProperty(name)
为此:

ConfigurationManager[name] = value
...
value = ConfigurationManager[name]
这并不能使代码变得更好;它不会比许多行代码小,由于autocomplete,编写起来也不容易,而且不太清晰,因为它隐藏了一个事实,即您正在获取和设置一个您称为“属性”的东西,它实际上迫使读者阅读有关索引器返回或设置的确切内容的文档,因为这一点并不明显,因为它是您正在为其编制索引的属性,而同时使用以下两种属性:

ConfigurationManager.editProperty(name, value);
...
value = ConfigurationManager.getProperty(name)
你可以大声读出来,并立即理解代码的作用


请记住,我们希望编写易于理解的代码,而不是编写速度快的代码。不要把编写代码的速度与完成项目的速度混为一谈。

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

public static class Config
{
   public static NameValueCollection Get => ConfigurationManager.AppSettings;
}
它还有一个额外的好处,即可以查找替换以升级旧代码并统一应用程序设置访问。

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

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

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

但遗憾的是,如果要将对象实际用作“值”类型,那么下面的代码将更短(至少作为声明),并且还提供即时类型转换:

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);
publicstatict加载(字符串键)=>elemDict.TryGetValue(键,out对象o)?(T) o:违约(T);
公共静态无效存储(字符串键,T值)=>elemdct[key]=value;
var cnt=元件负载(“计数器”);
元素存储(“计数器”,cnt);

但为什么索引器必须使用“thi”
public static class Config
{
   public static NameValueCollection Get => ConfigurationManager.AppSettings;
}
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;
        }
    }
}
var cnt = element["counter"] as int;
element["counter"] = cnt;
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);