C# 静态索引器?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/401232/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Static Indexers?
提问by Malfist
Why are static indexers disallowed in C#? I see no reason why they should not be allowed and furthermore they could be very useful.
为什么 C# 中不允许使用静态索引器?我认为没有理由不允许它们,而且它们可能非常有用。
For example:
例如:
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];
}
}
The above code would benefit greatly from a static indexer. However it won't compile because static indexers are not allowed. Why is this so?
上面的代码将从静态索引器中受益匪浅。但是它不会编译,因为不允许使用静态索引器。为什么会这样?
采纳答案by Juliet
Indexer notation requires a reference to this
. Since static methods don't have a reference to any particular instance of the class, you can't use this
with them, and consequently you can't use indexer notation on static methods.
索引器表示法需要对this
. 由于静态方法没有对类的任何特定实例的引用,因此不能this
与它们一起使用,因此不能对静态方法使用索引器表示法。
The solution to your problem is using a singleton pattern as follows:
您的问题的解决方案是使用单例模式,如下所示:
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
}
}
Now you can call Utilities.ConfigurationManager["someKey"]
using indexer notation.
现在您可以Utilities.ConfigurationManager["someKey"]
使用索引器符号进行调用。
回答by ChrisW
As a work-around, you can define an instance indexer on a singleton/static object (say that ConfigurationManager is a singleton, instead of being a static class):
作为解决方法,您可以在单例/静态对象上定义实例索引器(假设 ConfigurationManager 是单例,而不是静态类):
class ConfigurationManager
{
//private constructor
ConfigurationManager() {}
//singleton instance
public static ConfigurationManager singleton;
//indexer
object this[string name] { ... etc ... }
}
回答by Jon Skeet
I believe it was considered not to be terribly useful. I think it's a shame too - an example I tend to use is Encoding, where Encoding.GetEncoding("foo")
could be Encoding["Foo"]
. I don't think it would come up veryoften, but aside from anything else it just feels a little inconsistent not to be available.
我相信它被认为不是非常有用。我认为这也是一种耻辱——我倾向于使用的一个例子是编码,哪里Encoding.GetEncoding("foo")
可能是Encoding["Foo"]
. 我不认为这会拿出十分频繁,但除了别的它只是感觉有点不一致并不可用。
I would have to check, but I suspectit's available in IL (Intermediate Language) already.
我必须检查一下,但我怀疑它已经在 IL(中级语言)中可用。
回答by lamorach
The this keyword refers to the current instance of the class. Static member functions do not have a this pointer. The this keyword can be used to access members from within constructors, instance methods, and instance accessors.(retrieved from msdn). Since this references an instance of the class it conflicts with the nature of static, since static isn't associated with an instance of the class.
this 关键字指的是类的当前实例。静态成员函数没有 this 指针。this 关键字可用于从构造函数、实例方法和实例访问器中访问成员。(从msdn检索)。由于 this 引用了类的实例,因此它与静态的性质相冲突,因为静态与类的实例无关。
One workaround would be the following which allows you to use the indexer against a private Dictionary so you only need to create a new instance and you access the static part.
一种解决方法是以下方法,它允许您针对私有字典使用索引器,因此您只需要创建一个新实例并访问静态部分。
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>();
}
This allows you to skip the whole accessing a member of the class and just create an instance of it and index it.
这允许您跳过访问类成员的整个过程,只需创建它的一个实例并为其建立索引。
new ConfigurationManager()["ItemName"]
回答by pie
The reason is because it is quite hard to understand what exactly you are indexing with a static indexer.
原因是因为很难理解使用静态索引器索引的究竟是什么。
You say that the code would benefit from a static indexer, but would it really? All it would do is change this:
你说代码会从静态索引器中受益,但真的吗?它会做的就是改变这一点:
ConfigurationManager.editProperty(name, value);
...
value = ConfigurationManager.getProperty(name)
Into this:
进入这个:
ConfigurationManager[name] = value
...
value = ConfigurationManager[name]
which does not make the code better in any way; it is not smaller by many lines of code, it isn't easier to write thanks to autocomplete and it is less clear, as it hides the fact that you are getting and setting something you call 'Property' and it actually forces the reader to go read the documentation on what exactly the indexer returns or sets, because it is in no way obvious that it is a property that you are indexing for, while with both:
这不会以任何方式使代码更好;它并不比多行代码更小,由于自动完成,编写起来并不容易,而且不太清楚,因为它隐藏了您正在获取和设置称为“属性”的东西的事实,并且它实际上迫使读者请阅读有关索引器返回或设置的确切内容的文档,因为它是您正在索引的属性并不明显,而同时具有:
ConfigurationManager.editProperty(name, value);
...
value = ConfigurationManager.getProperty(name)
You can read it out loud and immediately understand what the code does.
您可以大声朗读并立即理解代码的作用。
Remember that we want to write code that is easy (= fast) to understand, not code that is fast to write. Do not mistake the speed at which you can lay down the code with the speed at which you complete projects.
请记住,我们希望编写易于理解(= 快速)的代码,而不是编写快速的代码。不要将编写代码的速度与完成项目的速度搞错了。
回答by vGHazard
With the newer constructs in C# 6, you might simplify the singleton pattern with a property expression body. For instance, I used the following shortcut which works nicely with code-lense:
使用 C# 6 中较新的构造,您可以使用属性表达式主体来简化单例模式。例如,我使用了以下快捷方式,它可以很好地与代码镜头配合使用:
public static class Config
{
public static NameValueCollection Get => ConfigurationManager.AppSettings;
}
It has the added benefit of being find-replace-able for upgrading older code and unifying your application settings access.
它还有一个额外的好处,即可以查找替换以升级旧代码并统一您的应用程序设置访问。
回答by DW.com
I was also in need (well, more like nice-to-have) of an static indexer to store attributes, so I figured out a somewhat awkward workaround:
我还需要(嗯,更像是一个很好的)静态索引器来存储属性,所以我想出了一个有点尴尬的解决方法:
Within the class you want to have an static indexer (here: Element), create a subclass of the same name + "Dict". Give it a readonly static as instance of said subclass, and then add your desired indexer.
在您想要静态索引器(此处:Element)的类中,创建一个同名的子类 +“Dict”。给它一个只读静态作为所述子类的实例,然后添加您想要的索引器。
Last, add the class as static import (hence the subclass to only expose the static field).
最后,将类添加为静态导入(因此子类仅公开静态字段)。
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;
}
}
}
and then you can use it either capitalized as Type, or without as dictionary:
然后您可以使用它作为 Type 大写,也可以不使用作为字典:
var cnt = element["counter"] as int;
element["counter"] = cnt;
But alas, if one were to actually use object as "value"-Type, then the below would be still shorter (at least as declaration), and also provide immediate Typecasting:
但是,唉,如果人们实际上将对象用作“值”类型,那么下面的内容会更短(至少作为声明),并且还提供立即类型转换:
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);