التحميل الزائد للمشغل مع البرمجة القائمة على الواجهة في C #

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

سؤال

خلفية

أنا أستخدم البرمجة المستندة إلى الواجهة على مشروع حالي واجهت مشكلة عند تحميل المشغلين (على وجه التحديد المشغلين للمساواة وعدم المساواة).


الافتراضات

  • أنا أستخدم C # 3.0، .NET 3.5 و Visual Studio 2008

تحديث - الافتراض التالي كان خطأ!

  • تتطلب جميع المقارنات لاستخدام متساوين بدلا من المشغل == ليس حلا قابل للتطبيق، خاصة عند تمرير أنواعك إلى المكتبات (مثل المجموعات).

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

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

وهذه واجهة المساواة

يتم استخدام واجهة IEQuatable بواسطة كائنات مجموعة عامة مثل القاموس والمدرجة، وربطها عند اختبار المساواة في هذه الأساليب كما تحتوي، indexof، lastindexof، وإزالة. يجب تنفيذها لأي كائن قد يتم تخزينه في مجموعة عامة.


غير طرف

  • يجب ألا يتطلب أي حل صب الكائنات من واجهاتهم لأنواعهم الخرسانية.

مشكلة

  • عندما تكون جانبي المشغل == هي واجهة، لا يوجد مشغل == توقيع طريقة الزائدة من أنواع الخرسانة الأساسية سيتطابق، وبالتالي سيتم استدعاء طريقة تشغيل الكائنات الافتراضية == الطريقة.
  • عند تحميل المشغل على الفصل، يجب أن يكون أحد معلمات المشغل الثنائية على الأقل، وإلا يتم إنشاء خطأ مترجم (خطأ BC33021 http://msdn.microsoft.com/en-us/library/watt39ff.aspx.)
  • ليس من الممكن تحديد التنفيذ على واجهة

انظر التعليمات البرمجية والإخراج أدناه إظهار المشكلة.


سؤال

كيف يمكنك توفير Overloads من المشغل المناسبة لفصولك عند استخدام البرمجة الأساسية الواجهة؟


مراجع

== المشغل (مرجع C #)

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


أنظر أيضا


رمز

using System;

namespace OperatorOverloadsWithInterfaces
{
    public interface IAddress : IEquatable<IAddress>
    {
        string StreetName { get; set; }
        string City { get; set; }
        string State { get; set; }
    }

    public class Address : IAddress
    {
        private string _streetName;
        private string _city;
        private string _state;

        public Address(string city, string state, string streetName)
        {
            City = city;
            State = state;
            StreetName = streetName;
        }

        #region IAddress Members

        public virtual string StreetName
        {
            get { return _streetName; }
            set { _streetName = value; }
        }

        public virtual string City
        {
            get { return _city; }
            set { _city = value; }
        }

        public virtual string State
        {
            get { return _state; }
            set { _state = value; }
        }

        public static bool operator ==(Address lhs, Address rhs)
        {
            Console.WriteLine("Address operator== overload called.");
            // If both sides of the argument are the same instance or null, they are equal
            if (Object.ReferenceEquals(lhs, rhs))
            {
                return true;
            }

            return lhs.Equals(rhs);
        }

        public static bool operator !=(Address lhs, Address rhs)
        {
            return !(lhs == rhs);
        }

        public override bool Equals(object obj)
        {
            // Use 'as' rather than a cast to get a null rather an exception
            // if the object isn't convertible
            Address address = obj as Address;
            return this.Equals(address);
        }

        public override int GetHashCode()
        {
            string composite = StreetName + City + State;
            return composite.GetHashCode();
        }

        #endregion

        #region IEquatable<IAddress> Members

        public virtual bool Equals(IAddress other)
        {
            // Per MSDN documentation, x.Equals(null) should return false
            if ((object)other == null)
            {
                return false;
            }

            return ((this.City == other.City)
                && (this.State == other.State)
                && (this.StreetName == other.StreetName));
        }

        #endregion
    }

    public class Program
    {
        static void Main(string[] args)
        {
            IAddress address1 = new Address("seattle", "washington", "Awesome St");
            IAddress address2 = new Address("seattle", "washington", "Awesome St");

            functionThatComparesAddresses(address1, address2);

            Console.Read();
        }

        public static void functionThatComparesAddresses(IAddress address1, IAddress address2)
        {
            if (address1 == address2)
            {
                Console.WriteLine("Equal with the interfaces.");
            }

            if ((Address)address1 == address2)
            {
                Console.WriteLine("Equal with Left-hand side cast.");
            }

            if (address1 == (Address)address2)
            {
                Console.WriteLine("Equal with Right-hand side cast.");
            }

            if ((Address)address1 == (Address)address2)
            {
                Console.WriteLine("Equal with both sides cast.");
            }
        }
    }
}

انتاج |

Address operator== overload called
Equal with both sides cast.
هل كانت مفيدة؟

المحلول

إجابة قصيرة: أعتقد أن افتراضك الثاني قد يختبئ. Equals() هي الطريقة الصحيحة للتحقق من المساواة الدلالية من كائنين، وليس operator ==.


إجابة طويلة: دقة الزائدة للمشغلين يؤديها في وقت الترجمة، وليس تشغيل الوقت.

ما لم يكن المحول البرمجي يمكن أن يعرف بشكل نهائي أنواع الكائنات التي تطبق فيها مشغلا على ذلك، فلن يترجم. منذ التحويل البرمجي لا يمكن أن يكون متأكدا من أن IAddress سيكون شيئا لديه تجاوز ل == يعرف، فإنه يعود إلى الافتراضي operator == بداية شئ System.Object.

لرؤية هذا أكثر وضوحا، حاول تحديد operator + بالنسبة Address وإضافة اثنين IAddress الحالات. ما لم يلقي صراحة Address, ، سوف تفشل في الترجمة. لماذا ا؟ لأن المحول البرمجي لا يمكن أن يخبر أنه معين IAddress هو Address, ، وليس هناك افتراضي operator + التنفيذ للعودة إلى الداخل System.Object.


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

تتطلب جميع المقارنات لاستخدام متساوين بدلا من المشغل == ليس حلا قابل للتطبيق، خاصة عند تمرير أنواعك إلى المكتبات (مثل المجموعات).

في رأيي، هذا هو بالضبط ما يجب أن تفعله. Equals() هي الطريقة الصحيحة للتحقق من المساواة الدلالية من كائنين. في بعض الأحيان المساواة الدلالية هي مجرد مساواة مرجعية، وفي هذه الحالة لن تحتاج إلى تغيير أي شيء. في حالات أخرى، كما في مثالك، ستجاوز Equals عندما تحتاج إلى عقد مساواة أقوى من المساواة المرجعية. على سبيل المثال، قد ترغب في النظر في اثنين Persons على قدم المساواة إذا كان لديهم نفس رقم الضمان الاجتماعي، أو اثنين Vehicles على قدم المساواة إذا كان لديهم نفس vin.

ولكن Equals() و operator == ليست هي نفس الشيء. كلما كنت بحاجة إلى تجاوز operator ==, ، يجب عليك تجاوز Equals(), ، ولكن تقريبا أبدا العكس. operator == هو أكثر من الراحة النحوية. لا تسمح لك بعض لغات CLR (مثل Visual Basic.net) بالتجاوز مشغل المساواة.

نصائح أخرى

ركضنا في نفس المشكلة، ووجدنا حل ممتاز: أنماط مخصصة resharper.

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

وشملت الكتالوج جميع الأنماط المعروفة أن تكون خاطئة في نظامنا:

$i1$ == $i2$ (حيث I1 و I2 التعبيرات من نوع واجهة لدينا، أو مشتقة.

نمط استبدال هو

$i1$.Equals($i2$)

والشدة "تظهر كخطأ".

وبالمثل لدينا $i1$ != $i2$

أتمنى أن يساعدك هذا. PS Catalogs Global هي الميزة في Rethharper 6.1 (EAP)، سيتم وضع علامة نهائية قريبا جدا.

تحديث: قدمت مسألة resharper. لوضع علامة على جميع الواجهة "==" تحذير ما لم تكن مقارنة ب NULL. يرجى التصويت إذا كنت تعتقد أنها ميزة جديرة.

تحديث 2.: .

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