C# كيفية إنشاء الحروف العامة والمحددات والأساليب الخاصة للمجموعة؟

StackOverflow https://stackoverflow.com/questions/1080644

  •  22-08-2019
  •  | 
  •  

سؤال

أرغب في الحصول على فئة "A" مع خاصية "SrtdLst" لمجموعة SortedList (على سبيل المثال)، وداخل هذه الفئة "A" تسمح بإضافة أو طرح عناصر "SrtdLst".ولكن في مثيل الفئة "أ"، يسمح فقط بالحصول على محتوى العناصر أو تعيينه، وليس إضافة عناصر جديدة أو طرح العناصر الموجودة.في الكود:

class A
{
    public SortedList<string, string> SrtdLst = new SortedList<string, string>();

    public A()
    {
        // This must work:
        SrtdLst.Add("KeyA", "ValueA");
        // This too:
        SrtdLst["KeyA"] = "ValueAAA";
    }
}

class B
{
    public A a = new A();
    public B()
    {
        // I want the following code to fail:
        a.SrtdLst.Add("KeyB", "ValueB");
        // But this must work:
        a.SrtdLst["KeyA"] = "ValueBBB";
   }
}

تحديث:أريد إنشاء فئة مثل System.Data.SqlClient.SqlCommand.بالنسبة للإجراءات المخزنة، يمكنك استخدام العضو "DeriveParameters" الذي يملأ مجموعة من "المعلمات"، بحيث يمكن تعديل قيمة كل عنصر فقط.

كيف يمكن القيام بذلك؟

هل كانت مفيدة؟

المحلول

إذا كنت تريد حظر عمليات التعديل في وقت الترجمة، فأنت بحاجة إلى حل آمن للنوع.

قم بتعريف واجهة للعمليات المسموح بها بشكل عام.استخدم تلك الواجهة كنوع الخاصية.

public interface IReadOnlyList<T>
{
    T this[int index] { get; }

    int Count { get; }
}

ثم أعلن عن فئة تنفذ تلك الواجهة وترث من فئة المجموعة القياسية.

public class SafeList<T> : List<T>, IReadOnlyList<T> { }

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

استخدم تلك الفئة المشتقة كنوع الحقل الذي يخزن قيمة الخاصية.

public class A
{
    private SafeList<string> _list = new SafeList<string>();

    public IReadOnlyList<string>
    {
        get { return _list; }
    }
}

ضمن الفئة (أ)، يمكنك استخدام _list مباشرة، وبالتالي تعديل المحتويات.لن يتمكن عملاء الفئة (أ) إلا من استخدام المجموعة الفرعية من العمليات المتاحة عبرها IReadOnlyList<T>.

على سبيل المثال، أنت تستخدم SortedList بدلاً من List، لذلك ربما تحتاج الواجهة إلى ذلك

public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
    V this[K index] { get; }        
}

لقد جعلته يرث IEnumerable أيضًا، وهو للقراءة فقط على أي حال، لذا فهو آمن تمامًا.ستكون الفئة الآمنة بعد ذلك:

public class SafeSortedList<K, V> : SortedList<K, V>, IReadOnlyDictionary<K, V> { }

لكن بخلاف ذلك فهي نفس الفكرة.

تحديث:لاحظت للتو أنك (لسبب ما لا أستطيع فهمه) لا تريد حظر عمليات التعديل - أنت فقط تريد حظر بعض عمليات التعديل.غريب جدًا، لكن لا يزال نفس الحل.مهما كانت العمليات التي تريد السماح بها، "افتحها" في الواجهة:

public interface IReadOnlyDictionary<K, V> : IEnumerable<KeyValuePair<K, V>>
{
    V this[K index] { get; set; }        
}

بالطبع، هذا الاسم الخاطئ للواجهة الآن...لماذا بحق السماء تريد حظر الإضافة عبر الإضافة ولكن لا تريد حظرها عبر المفهرس؟(يمكن استخدام المفهرس لإضافة عناصر، تمامًا كما تفعل طريقة الإضافة.)

تحديث

من تعليقك، أعتقد أنك تقصد أنك تريد السماح بالتخصيص لقيمة زوج المفتاح/القيمة الموجود، ولكن لا تسمح بالتخصيص لمفتاح غير معروف مسبقًا.من الواضح أنه يتم تحديد المفاتيح في وقت التشغيل بواسطة سلاسل، فلا توجد طريقة للتعرف على ذلك في وقت الترجمة.لذلك يمكنك أيضًا الذهاب للتحقق من وقت التشغيل:

public class FixedSizeDictionaryWrapper<TKey, TValue> : IDictionary<TKey, TValue>
{
    IDictionary<TKey, TValue> _realDictionary;

    public FixedSizeDictionaryWrapper(IDictionary<TKey, TValue> realDictionary)
    {
        _realDictionary = realDictionary;
    }

    public TValue this[TKey key]
    {
        get { return _realDictionary[key]; }

        set 
        {
            if (!_realDictionary.Contains(key))
                throw new InvalidOperationException();

            _realDictionary[key] = value;
        }
    }

    // Implement Add so it always throws InvalidOperationException

    // implement all other dictionary methods to forward onto _realDictionary
}

في أي وقت يكون لديك قاموسًا عاديًا وتريد تسليمه إلى طريقة لا تثق بها لتحديث القيم الموجودة، قم بتغليفه في واحدة منها.

نصائح أخرى

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

لماذا تريد تقييد تلك العملية الواحدة فقط؟


الجواب الأصلي

لسبب واحد، لا تستخدم الحقول العامة.هذه طريقة مؤكدة للوقوع في المشاكل.

يبدو أنك تريد فئة مجمعة للقراءة فقط بشكل تعسفي IDictionary.يمكنك بعد ذلك الحصول على خاصية عامة تقوم بإرجاع الغلاف، بينما يمكنك الوصول إلى المتغير الخاص من داخل صفك.على سبيل المثال:

class A
{
    private SortedList<string, string> sortedList = new SortedList<string, string>();

    public IDictionary<string, string> SortedList 
    {
        get { return new ReadOnlyDictionaryWrapper(sortedList);
    }

    public A()
    {
        sortedList.Add("KeyA", "ValueA");
        sortedList["KeyA"] = "ValueAAA";
    }
}

الآن عليك فقط العثور على ReadOnlyDictionary تطبيق...لا أستطيع تنفيذه الآن، ولكن سأعود لاحقاً إذا لزم الأمر...

وجعل مجرد قائمة خاصة، وكشف أنها مفهرس:

class A {

   private SortedList<string, string> _list;

   public A() {
      _list = new SortedList<string, string>()
   }

   public string this[string key] {
      get {
         return _list[key];
      }
      set {
         _list[key] = value;
      }
   }

}

والآن يمكنك فقط الوصول إلى العناصر باستخدام الفهرس:

a["KeyA"] = "ValueBBB";

ولكن، وكما مفهرس من قائمة يسمح بإنشاء عناصر جديدة، سيكون لديك لإضافة التعليمات البرمجية في مفهرس لمنع ذلك إذا كنت لا تريد أن تفعل يكون ممكنا.

إذا عرفت مفاتيح خارج الطبقة ثم يمكنك إضافة ChangeItem (مفتاح، NEWVALUE) وReadItem (مفتاح) لفئة المجمع الخاص بك. ثم حفاظ على SortedList خاصة إلى الفئة.

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