정적 인덱서?


119

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];
        }
    }

위의 코드는 정적 인덱서의 이점을 크게 활용할 수 있습니다. 그러나 정적 인덱서가 허용되지 않기 때문에 컴파일되지 않습니다. 왜 그렇습니까?


내가 할 수 있도록 다음으로, 정적 클래스에 직접 IEnumerable을 구현합니다 foreach (var enum in Enum):)
nawfal

답변:


72

인덱서 표기법에는에 대한 참조가 필요합니다 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"]인덱서 표기법을 사용하여 호출 할 수 있습니다 .


110
그러나 인덱서가 'this'를 사용해야하는 이유는 무엇입니까? 인스턴스 데이터에 액세스 할 필요가 없습니다
Malfist

80
Malfist의 댓글에 +1. 인스턴스 인덱서에 "this"를 사용한다고해서 다른 구문을 만들 수 없다는 의미는 아닙니다.
Jon Skeet

40
동의합니다. 당신은 질문을 구걸하고 있습니다. 기본적으로 허용되지 않는 이유는 허용되지 않기 때문이라고 말씀하셨습니다. -1 질문이 "왜 허용되지 않습니까?"였기 때문입니다.
xr280xr 2012

15
@ xr280xr +1 "질문을 구걸"의 올바른 사용을 위해 :) 또한 동일한 불만이 있습니다.
RedFilter

14
이 답변은 정적 인덱서가 구현 된 경우 현재 표기법이 유일한 표기법이라고 가정하기 때문에 -1입니다. 의 사용 this인덱서에 반드시이 가장 감각을 만들었 기 때문에 그것은 가능성이 다른 키워드 위에 선정되었다, 필요하지 않습니다. 정적 구현의 경우 다음 구문이 실행 가능할 수 있습니다 public object static[string value].. this정적 컨텍스트에서 키워드를 사용할 필요가 없습니다 .
einsteinsci

91

그다지 유용하지 않은 것으로 간주되었다고 생각합니다. 내가 너무 수치를 생각 - 내가 사용하는 경향이 예는 인코딩입니다 Encoding.GetEncoding("foo")될 수있다 Encoding["Foo"]. 나는 그것이 올 것이라고 생각하지 않는다 매우 자주하지만, 따로 다른 어떤에서 그것은 단지 약간의 일관성 사용할 수 없습니다 느낀다.

확인해야하지만 이미 IL (중간 언어)에서 사용할 수 있다고 생각 합니다.


6
중간 언어-.NET 용 어셈블리 언어의 일종.
Jon Skeet

15
저를 여기에 가져온 것은 정적 속성을 통해 애플리케이션 전체에서 사용되는 공통 값의 사전을 노출하는 사용자 정의 클래스가 있다는 것입니다. 정적 인덱서를 사용하여 GlobalState.State [KeyName]에서 GlobalState [KeyName]로 액세스를 줄이려고했습니다. 좋았을 텐데.
xr280xr 2012

1
FWIW 변화 instancestaticILASM의 불평 기본 속성 결과의 속성 게터 방법에 대한 IL syntax error at token 'static'; 나는 일리노이의 일에 개입하는 데 능숙하지 않지만 적어도 처음에는 아니오처럼 들립니다.
Amazingant 2015 년

8

해결 방법으로 싱글 톤 / 정적 개체에 인스턴스 인덱서를 정의 할 수 있습니다 (예 : ConfigurationManager가 정적 클래스가 아닌 싱글 톤이라고 가정).

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

1

또한 속성을 저장하기 위해 정적 인덱서가 필요했기 때문에 다소 어색한 해결 방법을 찾았습니다.

정적 인덱서 (여기서는 요소)를 원하는 클래스 내에서 동일한 이름 + "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);

0

C # 6의 최신 구문을 사용하면 속성 식 본문으로 싱글 톤 패턴을 단순화 할 수 있습니다. 예를 들어, 코드 렌스와 잘 작동하는 다음 단축키를 사용했습니다.

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

이전 코드를 업그레이드하고 애플리케이션 설정 액세스를 통합하기 위해 찾기-교체 가능하다는 추가 이점이 있습니다.


-2

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"]

4
흥미로운 해결 방법이지만 1) 일부 환경에서 메모리 압력 및 조각화로 이어질 수있는 부작용 (빈 인스턴스 개체 생성)이 도입됩니다. 2) 낭비되는 추가 문자 new ()가 싱글 톤의 한정자 이름에 사용될 수 있습니다. 대신, 같은.Current
로렌스 구

1
Juliet의 답변 과 마찬가지로 정적 인덱서가 지원되지 않는 이유에 대한 답변은 아닙니다. 첫째, 질문은 "정적 인덱서"라는 용어를 " this키워드 를 사용하는 것"으로 제한하지 않습니다. 둘째, this구문 public string this[int index]에서 엄격히 말하면 this포인터를 사용하지 않습니다 (인스턴스 메서드 본문에서 발생할 수 있음). ,하지만 토큰 의 또 다른 용도입니다 this. 구문 public static string this[int index]은 다소 직관적이지 않은 것처럼 보일 수 있지만 여전히 모호하지 않습니다.
또는 Mapper

2
@ORMapper 그것도 될 수 있습니다 public static string class[int index].
Jim Balter 2015-07-28

'이 키워드는 클래스의 현재 인스턴스를 나타냅니다. 정적 멤버 함수에는 this 포인터가 없습니다. ' 참조 할 this 포인터에 대한 개체가 없기 때문에 참조를 사용할 수 없다고 설명했습니다. 그리고 나는 또한 msdn이 그 정의를 사용하는 사람이라고 말했습니다. 공개 정적 문자열 대 공개 문자열은 하나는 제네릭 유형 객체에 액세스하고 다른 하나는 인스턴스 객체에 액세스한다는 사실로 인해 내 지식에 겹치지 않습니다.
lamorach

-2

그 이유는 정적 인덱서로 정확히 무엇을 인덱싱하고 있는지 이해하기가 매우 어렵 기 때문입니다.

코드가 정적 인덱서의 이점을 얻을 수 있다고 말했지만 실제로는 그럴까요? 이것이 할 일은 이것을 변경하는 것입니다.

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

이것으로 :

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

어떤 식 으로든 코드를 더 좋게 만들지는 않습니다. 여러 줄의 코드로 작지 않고 자동 완성 기능 덕분에 작성하기가 더 쉽지 않으며 '속성'이라고 부르는 것을 얻고 설정한다는 사실을 숨기고 실제로 독자가 인덱서가 반환하거나 설정하는 것이 무엇인지에 대한 설명서를 읽으십시오. 두 가지 모두를 사용하는 동안 인덱싱하는 속성이 분명하지 않기 때문입니다.

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

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

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


8
동의하지 않는다. 그것은 단지 개념적 요점입니다. 제 생각에는 코드가 더 나아 보입니다.
ouflak
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.