سؤال

لماذا لا يُسمح بالفهارس الثابتة في 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 ... }
}

ومع بنيات جديدة في C # 6، قد تبسيط نمط المفرد مع هيئة التعبير الممتلكات. على سبيل المثال، وأنا استخدم الاختصار التالية التي تعمل بشكل جيد مع رمز ينس:

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

وان لها فائدة إضافية تتمثل في أن تجد-محل-قادرة على تطوير كود السن وتوحيد الوصول إعدادات التطبيق.

وكنت أيضا في حاجة إلى (حسنا، أشبه-لطيفة إلى أن يكون) من مفهرس ثابت لتخزين الصفات، ولذا فإنني أحسب حلا محرجا بعض الشيء:

وضمن الفئة التي تريد أن يكون لها مفهرس ثابت (هنا: العنصر)، إنشاء فئة فرعية من نفس الاسم + "ديكت". إعطائها ثابت للقراءة فقط كما قال مثيل فئة فرعية، ثم قم بإضافة مفهرس المطلوب.

وأخيرا، إضافة فئة كما استيراد ثابت (وبالتالي فرعية فقط لفضح حقل ثابت).

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

وبعد ذلك يمكنك استخدامه إما رسملتها نوع، أو بدون كما القاموس:

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

ولكن للأسف، إذا كان للمرء فعلا لاستخدام الكائن باسم "قيمة" من نوع، ثم أدناه سيظل أقصر (على الأقل كما إعلان)، وكذلك تقديم تلبيس فوري:

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

وهذه الكلمة تشير إلى الحالة الراهنة للفئة. وظائف عضو ثابت لم يكن لديك هذا المؤشر. وهذه الكلمة يمكن استخدامها لأعضاء الوصول من داخل منشئات وأساليب سبيل المثال، ويمكنهم الدخول سبيل المثال. (استردادها من <لأ href = "http://msdn.microsoft.com/en-us/library/dk1507sz٪28v=vs. 71٪ 29.ASPX "يختلط =" نوفولو "> MSDN ). وبما أن هذا يحيل مثيل الطبقة ذلك يتعارض مع طبيعة ثابتة، لأن ثابت لا يرتبط مع مثيل الطبقة.

والحل واحد ستكون التالية والتي تتيح لك استخدام مفهرس ضد القطاع الخاص قاموس لذلك أنت تحتاج فقط إلى إنشاء مثيل جديد ويمكنك الوصول إلى جزء ثابت.

    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)

ويمكن أن تقرأ بصوت عال وفهم على الفور ما يفعله التعليمات البرمجية.

تذكر أننا نريد أن كتابة التعليمات البرمجية التي هي سهلة (= سريع) لفهم، وليس رمز التي هي سريعة في الكتابة. لا خطأ السرعة التي يمكنك وضع رمز مع السرعة التي كنت مشاريع كاملة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top