سؤال

هل هناك طريقة لاختبار ما إذا كان الكائن عبارة عن قاموس؟

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

أود أن أفعل شيئًا مشابهًا لهذا:

if (listBox.ItemsSource is Dictionary<??>)
{
    KeyValuePair<??> pair = (KeyValuePair<??>)listBox.SelectedItem;
    object value = pair.Value;
}

هل هناك طريقة للقيام بذلك ديناميكيًا في وقت التشغيل باستخدام الانعكاس؟أعلم أنه من الممكن استخدام الانعكاس مع الأنواع العامة وتحديد معلمات المفتاح/القيمة، لكنني لست متأكدًا مما إذا كانت هناك طريقة للقيام بالباقي بعد استرداد تلك القيم.

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

المحلول

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

if (listBox.ItemsSource.IsGenericType && 
    typeof(IDictionary<,>).IsAssignableFrom(listBox.ItemsSource.GetGenericTypeDefinition()))
{
    var method = typeof(KeyValuePair<,>).GetProperty("Value").GetGetMethod();
    var item = method.Invoke(listBox.SelectedItem, null);
}

نصائح أخرى

تحقق لمعرفة ما إذا كان يطبق IDictionary.

راجع تعريف System.Collections.IDictionary لمعرفة ما يقدمه لك ذلك.

if (listBox.ItemsSource is IDictionary)
{
    DictionaryEntry pair = (DictionaryEntry)listBox.SelectedItem;
    object value = pair.Value;
}

يحرر:بديل عندما أدركت أن KeyValuePair غير قابلة للتحويل إلى DictionaryEntry

if (listBox.DataSource is IDictionary)
{
     listBox.ValueMember = "Value";
     object value = listBox.SelectedValue;
     listBox.ValueMember = ""; //If you need it to generally be empty.
}

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

أعلم أن هذا السؤال تم طرحه منذ سنوات عديدة، لكنه لا يزال مرئيًا للعامة.

كانت هناك بعض الأمثلة المقترحة هنا في هذا الموضوع وفي هذا الموضوع:
تحديد ما إذا كان النوع هو القاموس [مكرر]

ولكن هناك القليل من حالات عدم التطابق، لذا أريد مشاركة الحل الذي توصلت إليه

اجابة قصيرة:

var dictionaryInterfaces = new[]
{
    typeof(IDictionary<,>),
    typeof(IDictionary),
    typeof(IReadOnlyDictionary<,>),
};

var dictionaries = collectionOfAnyTypeObjects
    .Where(d => d.GetType().GetInterfaces()
        .Any(t=> dictionaryInterfaces
            .Any(i=> i == t || t.IsGenericType && i == t.GetGenericTypeDefinition())))

إجابة أطول:
أعتقد أن هذا هو سبب ارتكاب الناس للأخطاء:

//notice the difference between IDictionary (interface) and Dictionary (class)
typeof(IDictionary<,>).IsAssignableFrom(typeof(IDictionary<,>)) // true 
typeof(IDictionary<int, int>).IsAssignableFrom(typeof(IDictionary<int, int>)); // true

typeof(IDictionary<int, int>).IsAssignableFrom(typeof(Dictionary<int, int>)); // true
typeof(IDictionary<,>).IsAssignableFrom(typeof(Dictionary<,>)); // false!! in contrast with above line this is little bit unintuitive

فلنفترض أن لدينا هذه الأنواع:

public class CustomReadOnlyDictionary : IReadOnlyDictionary<string, MyClass>
public class CustomGenericDictionary : IDictionary<string, MyClass>
public class CustomDictionary : IDictionary

وهذه الحالات:

var dictionaries = new object[]
{
    new Dictionary<string, MyClass>(),
    new ReadOnlyDictionary<string, MyClass>(new Dictionary<string, MyClass>()),
    new CustomReadOnlyDictionary(),
    new CustomDictionary(),
    new CustomGenericDictionary()
};

لذلك إذا كنا سنستخدم طريقة .IsAssignableFrom() :

var dictionaries2 = dictionaries.Where(d =>
    {
        var type = d.GetType();
        return type.IsGenericType && typeof(IDictionary<,>).IsAssignableFrom(type.GetGenericTypeDefinition());
    }); // count == 0!!

لن نحصل على أي مثال

لذا فإن أفضل طريقة هي الحصول على جميع الواجهات والتحقق مما إذا كان أي منها عبارة عن واجهة قاموس:

var dictionaryInterfaces = new[]
{
    typeof(IDictionary<,>),
    typeof(IDictionary),
    typeof(IReadOnlyDictionary<,>),
};

var dictionaries2 = dictionaries
    .Where(d => d.GetType().GetInterfaces()
        .Any(t=> dictionaryInterfaces
            .Any(i=> i == t || t.IsGenericType && i == t.GetGenericTypeDefinition()))) // count == 5

يمكنك التحقق لمعرفة ما إذا كان سيتم تنفيذه معرف القاموس.سيكون عليك فقط تعداد استخدام دخول القاموس فصل.

يمكنك أن تكون أكثر عمومية وتسأل بدلاً من ذلك عما إذا كان سيتم تنفيذه IDictionary.ثم ستستمر مجموعة KeyValue بشكل عادي Objects.

أعتقد أن التحذير موجود.

عندما تختبر ما إذا كان الكائن "هو" شيء ما هذا أو ذاك، فإنك تعيد تنفيذ (جزء من) نظام الكتابة.غالبًا ما يتبع الحرف الأول "a" سريعًا حرف ثانٍ، وسرعان ما تمتلئ التعليمات البرمجية الخاصة بك بعمليات التحقق من النوع، والتي يجب أن يتعامل معها نظام الكتابة جيدًا - على الأقل في التصميم الموجه للكائنات.

وبالطبع لا أعلم شيئًا عن سياق السؤال.أعرف ملفًا مكونًا من 2000 سطر في قاعدة التعليمات البرمجية الخاصة بنا والذي يتعامل مع 50 كائنًا مختلفًا لتحويلات السلسلة...:(

if(typeof(IDictionary).IsAssignableFrom(listBox.ItemsSource.GetType()))
{

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