[C#] 정적 인덱서?

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)

소리내어 읽고 코드가하는 일을 즉시 이해할 수 있습니다.

빠른 코드가 아니라 이해하기 쉬운 (= 빠른) 코드를 작성하고 싶다는 것을 기억하십시오. 프로젝트를 완료하는 속도와 코드를 놓을 수있는 속도를 착각하지 마십시오.