静态索引器?

为什么在 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];
}
}

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

50448 次浏览

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

class ConfigurationManager
{
//private constructor
ConfigurationManager() {}
//singleton instance
public static ConfigurationManager singleton;
//indexer
object this[string name] { ... etc ... }
}

索引器符号需要对 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"]

我相信它被认为不是特别有用。我认为这也是一种耻辱——我倾向于使用的一个例子是编码,其中 Encoding.GetEncoding("foo")可以是 Encoding["Foo"]。我不认为它会经常出现在 非常,但除了其他任何东西,它只是觉得有点不一致,不可用。

我将不得不检查,但我 疑犯它在白细胞介素(中间语言)已经可用。

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

这允许您跳过访问类成员的整个过程,只需创建该类的实例并对其进行索引。

    new ConfigurationManager()["ItemName"]

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

您说代码将从静态索引器中受益,但它真的会受益吗?它只会改变这一点:

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

变成这样:

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

这并没有让代码在任何方面变得更好; 它并没有小很多行代码,它不是更容易编写感谢自动补全,它不那么清晰,因为它隐藏了事实,你正在获取和设置的东西,你称为“属性”,它实际上迫使读者去阅读文档,究竟是什么索引器返回或设置,因为它是一个明显的方式,你正在索引的属性,而两者:

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

您可以大声读出它,并立即理解代码的作用。

请记住,我们希望编写易于理解(= 快速)的代码,而不是编写快速的代码。不要把编写代码的速度和完成项目的速度搞错了。

使用 C # 6中较新的结构,您可以使用一个属性表达式主体来简化单例模式。 例如,我使用了下面的快捷方式,它可以很好地与代码镜头一起工作:

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

它还有一个额外的好处,就是可以用来升级旧代码和统一应用程序设置访问。

我也需要一个静态索引器来存储属性,所以我想出了一个有点尴尬的解决办法:

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

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

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,也可以不用作 dictionary:

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

但是,如果实际上使用 object 作为“ value”-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);