في C# 4.0 لماذا لا يمكن أن تكون المعلمة out في الطريقة متغيرة؟

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

  •  22-08-2019
  •  | 
  •  

سؤال

بالنظر إلى هذه الواجهة السحرية:

public interface IHat<out TRabbit>
{
    TRabbit Take();
}

وهذا التسلسل الهرمي للفئة:

public class Rabbit { }

public class WhiteRabbit : Rabbit { }

يمكنني الآن تجميع هذا:

IHat<WhiteRabbit> hat1 = null;
IHat<Rabbit> hat2 = hat1;

وهو أمر عظيم.ولكن ماذا لو قمت بتعريف الواجهة بشكل مختلف:

public interface IHat<out TRabbit>
{
    bool Take(out TRabbit r);
}

أشير إلى أن القبعة قد تكون فارغة، باستخدام قيمة إرجاع منطقية منفصلة (ربما كان الإصدار السابق قد أعاد أرنبًا فارغًا من قبعة فارغة).لكنني لا أزال أخرج أرنبًا فقط، لذا لا أفعل أي شيء مختلف منطقيًا عن الإصدار السابق.

يعطي برنامج التحويل البرمجي C# 4.0 في CTP خطأً في تعريف الواجهة - فهو يتطلب أن تكون معلمات الأسلوب "out" من النوع الثابت.هل هناك سبب قوي وسريع لعدم السماح بذلك، أم أنه شيء يمكن معالجته في إصدار مستقبلي؟

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

المحلول

ومثيرة للاهتمام. ومع ذلك، على المستوى CLI لا يوجد شيء مثل "الخروج" - فقط "المرجع". هناك سمة التي تساعد المجمعين (لمهمة محددة) التي تقول "لا تحتاج إلى تمريرها في".

وربما يكون هذا التقييد لأن CLI لم يكن لديك "الخروج"، فقط "المرجع".

نصائح أخرى

على الرغم من أن الأمر مزعج بعض الشيء، إلا أنه يمكنك استخدام غلاف التغاير:

public class CovariantListWrapper<TOut, TIn> : IList<TOut> where TIn : TOut
{
    IList<TIn> list;

    public CovariantListWrapper(IList<TIn> list)
    {
        this.list = list;
    }

    public int IndexOf(TOut item)
    {
        // (not covariant but permitted)
        return item is TIn ? list.IndexOf((TIn)item) : -1;
    }

    public TOut this[int index]
    {
        get { return list[index]; }
        set { throw new InvalidOperationException(); }
    }

    public bool Contains(TOut item)
    {
        // (not covariant but permitted)
        return item is TIn && list.Contains((TIn)item);
    }

    public void CopyTo(TOut[] array, int arrayIndex)
    {
        foreach (TOut t in this)
            array[arrayIndex++] = t;
    }

    public int Count { get { return list.Count; } }

    public bool IsReadOnly { get { return true; } }

    public IEnumerator<TOut> GetEnumerator()
    {
        foreach (TIn t in list)
            yield return t;
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Insert(int index, TOut item) { throw new InvalidOperationException(); }
    public void RemoveAt(int index) { throw new InvalidOperationException(); }
    public void Add(TOut item) { throw new InvalidOperationException(); }
    public void Clear() { throw new InvalidOperationException(); }
    public bool Remove(TOut item) { throw new InvalidOperationException(); }
}

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

class CovarianceWrapperExample
{
    class Person { }
    class Employee : Person { }

    void ProcessPeople(IList<Person> people) { /* ... */ }

    void Foo()
    {
        List<Employee> employees = new List<Employee>();

        // cannot do:
        ProcessPeople(employees);

        // can do:
        ProcessPeople(new CovariantListWrapper<Person, Employee>(employees));
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top