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];
}
}
위의 코드는 정적 인덱서의 이점을 크게 활용할 수 있습니다. 그러나 정적 인덱서가 허용되지 않기 때문에 컴파일되지 않습니다. 왜 그렇습니까?
답변
인덱서 표기법에는에 대한 참조가 필요합니다 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"]
. 나는 그것이 올 것이라고 생각하지 않는다 매우 자주하지만, 따로 다른 어떤에서 그것은 단지 약간의 일관성 사용할 수 없습니다 느낀다.
확인해야하지만 이미 IL (중간 언어)에서 사용할 수 있다고 생각 합니다.
답변
해결 방법으로 싱글 톤 / 정적 개체에 인스턴스 인덱서를 정의 할 수 있습니다 (예 : ConfigurationManager가 정적 클래스가 아닌 싱글 톤이라고 가정).
class ConfigurationManager
{
//private constructor
ConfigurationManager() {}
//singleton instance
public static ConfigurationManager singleton;
//indexer
object this[string name] { ... etc ... }
}
답변
또한 속성을 저장하기 위해 정적 인덱서가 필요했기 때문에 다소 어색한 해결 방법을 찾았습니다.
정적 인덱서 (여기서는 요소)를 원하는 클래스 내에서 동일한 이름 + “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으로 사용한다면, 아래는 여전히 더 짧을 것입니다 (적어도 선언으로). 또한 즉각적인 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);
답변
C # 6의 최신 구문을 사용하면 속성 식 본문으로 싱글 톤 패턴을 단순화 할 수 있습니다. 예를 들어, 코드 렌스와 잘 작동하는 다음 단축키를 사용했습니다.
public static class Config
{
public static NameValueCollection Get => ConfigurationManager.AppSettings;
}
이전 코드를 업그레이드하고 애플리케이션 설정 액세스를 통합하기 위해 찾기-교체 가능하다는 추가 이점이 있습니다.
답변
this 키워드는 클래스의 현재 인스턴스를 참조합니다. 정적 멤버 함수에는 this 포인터가 없습니다. this 키워드는 생성자, 인스턴스 메서드 및 인스턴스 접근 자 내에서 멤버에 액세스하는 데 사용할 수 있습니다 ( msdn 에서 검색 됨 ). 이것은 클래스의 인스턴스를 참조하기 때문에 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)
소리내어 읽고 코드가하는 일을 즉시 이해할 수 있습니다.
빠른 코드가 아니라 이해하기 쉬운 (= 빠른) 코드를 작성하고 싶다는 것을 기억하십시오. 프로젝트를 완료하는 속도와 코드를 놓을 수있는 속도를 착각하지 마십시오.