سؤال

لن تسمح لغة C# بكتابة وظائف غير الأعضاء ويجب أن تكون كل طريقة جزءًا من الفصل الدراسي.كنت أفكر في هذا باعتباره قيدًا في جميع لغات CLI.لكنني كنت مخطئًا ووجدت أن C++/CLI يدعم وظائف غير الأعضاء.عندما يتم تجميعه، سيجعل المترجم الطريقة عضوًا في فئة غير مسماة.

إليك ما يقوله معيار C++/CLI،

[ملحوظة:يتم التعامل مع الوظائف غير الأعضاء بواسطة واجهة سطر الأوامر (CLI) كأعضاء في فئة غير مسماة؛ومع ذلك، في كود مصدر C++/CLI، لا يمكن تأهيل مثل هذه الوظائف بشكل صريح باستخدام اسم الفئة هذا.ملاحظة النهاية]

تشفير الوظائف غير الأعضاء في البيانات التعريفية غير محدد.[ملحوظة:لا يتسبب هذا في حدوث مشكلات في التشغيل المتداخل لأن هذه الوظائف لا يمكن أن تتمتع برؤية عامة.ملاحظة النهاية]

لذا سؤالي هو لماذا لا تقوم لغة C# بتنفيذ شيء كهذا؟أو هل تعتقد أنه لا ينبغي أن تكون هناك وظائف غير الأعضاء ويجب أن تنتمي كل طريقة إلى فئة معينة؟

رأيي هو الحصول على دعم وظيفة غير الأعضاء ويساعد على تجنب تلويث واجهة الفصل.

أي أفكار..؟

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

المحلول

وانظر هذا بلوق نشر:

http://blogs.msdn.com/ericlippert/archive/2009/06/22/why-doesn-tc-implement-top-level-methods.aspx

<اقتباس فقرة>   

و(...)

     

وطلب مني "لماذا لا C # تطبيق ميزة X؟" طوال الوقت. الجواب هو نفسه دائما: لأنه لا يوجد واحد مصمم من أي وقت مضى، محددة، تنفذ، واختبارها وتوثيقها وشحنها هذه الميزة. كل ستة من تلك الأشياء ضرورية لجعل ميزة يحدث. كل منهم يكلف مبالغ كبيرة من الوقت والجهد والمال. ميزات ليست رخيصة، ونحن نحاول بجد للتأكد من أننا الشحن فقط تلك الميزات التي تعطي أفضل الفوائد الممكنة لمستخدمينا نظرا لدينا الوقت مقيدة والجهد والمال الميزانيات.

     

وأنا أفهم أن مثل هذه إجابة عامة ربما لا يعالج مسألة محددة.

     

في هذه الحالة بالذات، كان صالح المستخدم واضحة في الماضي ليست كبيرة بما يكفي لتبرير مضاعفات للغة التي من شأنها أن تترتب على ذلك. بواسطة stricting كيف مختلف الكيانات اللغة العش داخل بعضها البعض لدينا (1) تقييد البرامج القانونية أن يكون بأسلوب مشترك يسهل فهمها، و (2) تجعل من الممكن لتحديد "معرف بحث" القواعد التي مفهومة، specifiable، للتنفيذ، قابلة للاختبار وتوثيقها.

     

وعن طريق تقييد الهيئات طريقة ليكون دائما داخل البنية أو فئة، نحن تجعل من السهل على العقل عن معنى معرف غير مؤهلين المستخدمة في سياق الاحتجاج. شيء من هذا القبيل هو دائما عضو الاحتجاج بحالة من النوع الحالي (أو نوع قاعدة).

     

و(...)

وهذا النشر المتابعة:

HTTP: //blogs.msdn.com/ericlippert/archive/2009/06/24/it-already-is-a-scripting-language.aspx

<اقتباس فقرة>   

و(...)

     

ومثل كل قرارات التصميم، ونحن عندما نواجه عددا من الأفكار المتنافسة، مقنعة وقيمة وnoncompossible، لقد وصلنا إلى إيجاد حل وسط عملي. ونحن لا نفعل ذلك إلا على النظر في جميع possibilites ، أو وهو ما نقوم به في هذه القضية.

(التشديد من النص الأصلي)

نصائح أخرى

C# لا تسمح بذلك لأن Java لم تسمح بذلك.

يمكنني التفكير في عدة أسباب وراء عدم سماح مصممي Java بذلك

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

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

في لغة C++، حيث يُسمح بالوظائف غير الأعضاء، غالبًا ما يتم تفضيلها لعدة أسباب:

  • يساعد على التغليف.كلما قل عدد الأساليب التي يمكنها الوصول إلى الأعضاء الخاصين في الفصل، أصبح من الأسهل إعادة هيكلة هذا الفصل أو صيانته.يعد التغليف جزءًا مهمًا من OOP.
  • يمكن إعادة استخدام الكود بشكل أسهل عندما لا يكون جزءًا من الفصل الدراسي.على سبيل المثال، تحدد مكتبة C++ القياسية std::find أو std::sort` كوظائف غير عضو، بحيث يمكن إعادة استخدامها على أي نوع من التسلسلات، سواء كانت مصفوفات أو مجموعات أو قوائم مرتبطة أو (على الأقل std::find) التدفقات.تعد إعادة استخدام الكود أيضًا جزءًا مهمًا من OOP.
  • إنه يمنحنا فصلًا أفضل.ال find لا تحتاج الوظيفة إلى معرفة فئة LinkedList حتى تتمكن من العمل عليها.إذا تم تعريفها على أنها وظيفة عضو، فستكون عضوًا في فئة LinkedList، حيث تقوم بشكل أساسي بدمج المفهومين في نقطة واحدة كبيرة.
  • القابلية للتوسعة.إذا قبلت أن واجهة الفصل ليست فقط "جميع أعضائه العموميين"، ولكن أيضًا "جميع الوظائف غير الأعضاء التي تعمل في الفصل"، يصبح من الممكن توسيع واجهة الفصل دون الحاجة إلى التحرير أو حتى إعادة ترجمة الفصل نفسه.

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

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

http://www.ddj.com/cpp/184401197 و http://www.gotw.ca/publications/mill02.htm مقالتان كتبهما خبراء C++ حول هذا الموضوع.

وظائف غير عضو هي شيء جيد لأنهم تحسين التغليف والحد من اقتران بين أنواع. معظم لغات البرمجة الحديثة مثل هاسكل وF # دعم وظائف خالية.

ما هو صالح <م> لا وضع كل أسلوب في فئة المسمى؟ لماذا وظيفة غير عضو "تلوث" واجهة الفئة التي؟ إذا كنت لا تريد ذلك كجزء من API العام من فئة، إما لا تجعل الجمهور أو عدم وضعه في تلك الفئة. يمكنك دائما إنشاء فئة مختلفة.

لا أستطيع أن أتذكر أي وقت مضى يريد أن يكتب طريقة تطوف مع عدم وجود النطاق المناسب - بخلاف وظائف مجهولة، وبطبيعة الحال (التي ليست في الواقع نفسه)

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

ووCLS (مواصفات لغة مشتركة) تقول أنه يجب أن لا يكون لها وظائف غير الأعضاء في مكتبة الذي يتوافق مع CLS. انها مثل مجموعة إضافية من القيود بالإضافة إلى القيود الأساسية للCLI (واجهة لغة مشتركة).

ومن الممكن أن النسخة المقبلة من C # سيضيف القدرة على الكتابة توجيها using التي تسمح ليتم الوصول إلى أعضاء ثابتة من فئة دون تأهيل اسم الفئة:

using System.Linq.Enumerable; // Enumerable is a static class

...

IEnumerable<int> range = Range(1, 10); // finds Enumerable.Range

وبعد ذلك سوف تكون هناك حاجة لتغيير CLS والمكتبات القائمة.

<وأ href = "http://blogs.msdn.com/lucabol/archive/2008/04/08/ac-library-to-write-functional-code-part-ii-tuples.aspx" يختلط = "نوفولو noreferrer"> هذه بلوق وظائف يبرهن على وجود مكتبة للبرمجة وظيفية في C #، وأنها تستخدم اسم الفئة التي هي مجرد حرف واحد طويل، في محاولة لخفض الضوضاء الناجمة عن شرط التأهل لاستدعاءات الأسلوب ثابتة . والأمثلة من هذا القبيل أن تكون ألطف قليلا إذا توجيهات using يمكن أن تستهدف الطبقات.

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

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

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

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

على سبيل المثال، يمكن التعامل مع بعض الأشياء التي قد ترغب في الحصول عليها من أجلها طرق التمديد

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

أيضًا، لا ينبغي عليك بالضرورة مقارنة نموذج كائن C++ مع C#.C++ متوافقة إلى حد كبير (ولكن ليس تمامًا) مع لغة C، التي لم يكن لديها نظام فئة على الإطلاق - لذلك كان على C++ دعم لغة البرمجة هذه من تراث C، وليس لأي ضرورة تصميمية معينة.

ضع شيئًا في الاعتبار:تعد لغة C++ لغة أكثر تعقيدًا من لغة C#.وعلى الرغم من أنها قد تكون متشابهة من الناحية النحوية، إلا أنها وحوش مختلفة تمامًا من الناحية الدلالية.لن تظن أنه سيكون من الصعب للغاية إجراء تغيير كهذا، لكني أستطيع أن أرى كيف يمكن أن يحدث ذلك.لدى ANTLR صفحة ويكي جيدة تسمى ما الذي يجعل مشكلة اللغة صعبة؟ من الجيد التشاور بشأن أسئلة مثل هذه.في هذه الحالة:

معجم حساس للسياق؟لا يمكنك تحديد رمز المفردات الذي تريد مطابقته إلا إذا كنت تعرف نوع الجملة التي تقوم بتحليلها.

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

أيضًا، إذا صادف المترجم طريقة مثل هذه:

public void Foo()
{
    Bar();
}

...يجب عليه الآن الإجابة على السؤال "هل يقع Bar ضمن هذه الفئة أم أنها فئة عالمية؟"

مراجع أمامية أم خارجية؟على سبيل المثال، هناك حاجة إلى تمريرات متعددة؟لدى Pascal مرجع "أمامي" للتعامل مع مراجع الإجراءات داخل الملف، ولكنه يشير إلى الإجراءات في ملفات أخرى عبر بنود USES وما إلى ذلك...تتطلب معالجة خاصة.

وهذا شيء آخر يسبب المشاكل.تذكر أن لغة C# لا تتطلب إعلانات إعادة التوجيه.سيقوم المترجم بإجراء تمريرة واحدة فقط لتحديد الفئات التي تمت تسميتها والوظائف التي تحتوي عليها تلك الفئات.الآن عليك أن تقلق بشأن العثور على الفصول الدراسية و وظائف حيث يمكن أن تكون الوظائف إما داخل أو خارج الفصل.هذا شيء لا داعي للقلق بشأنه بالنسبة لمحلل C++ لأنه يقوم بتحليل كل شيء بالترتيب.

الآن لا تفهموني خطأ، من المحتمل أن يتم ذلك في C#، وربما سأستخدم مثل هذه الميزة.ولكن هل يستحق الأمر حقًا كل هذا العناء للتغلب على هذه العوائق عندما يمكنك فقط كتابة اسم فئة أمام طريقة ثابتة؟

وظائف الحرة هي مفيدة جدا إذا كنت الجمع بينها وبين الكتابة بطة. ويستند STL C ++ كله على ذلك. وبالتالي أنا متأكد من أن C # سوف أعرض وظائف خالية عندما تمكنوا من إضافة الوراثة الحقيقية.

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

ولئن كان صحيحا كنت في حاجة الى فئة (على سبيل المثال فئة ثابتة تسمى FreeFunctions) لعقد مثل هذه الوظائف، أنت حر لوضع using static FreeFunctions; في الجزء العلوي من أي ملف يحتاج إلى وظائف من ذلك، دون الحاجة إلى القمامة الشفرة مع تصفيات FreeFunctions.. لست متأكدا ما إذا كان هناك الحالة التي يكون فيها هذا هو أدنى واضح للا تتطلب تعريفات الدالة لتكون واردة في فئة. في الواقع

إذا فكرت في الأمر، ستكون الحجة المضادة "لماذا لا يدعم C++ طرق الامتداد" والإجابة تكمن في أهداف التصميم الخاصة بهم.

يمنحك C++ وظائف مساحة الاسم التي يمكنك استدعاؤها على أي كائن والتي من شأنها أن تساعدك على "توسيع" هذا الكائن بطريقة ما.

في معظم الأوقات التي استخدمت فيها وظائف مساحة الاسم في C++ كانت لإنشاء وظائف تقبل الكائنات وتقوم بوظائف لا أريد وضعها داخل وظيفة عضو في الفصل.

في C#، يمكنك إنشاء طريقة ملحقة تؤدي المهمة نيابةً عنك (في معظم الأوقات).بالنسبة لما تبقى من الحالات ستفتقد هذه الميزة.

خذ الكود التالي على سبيل المثال:

template<typename T>
unsigned int findCount(vector<T>& vec, T data){
    unsigned int count = 0;
    for(auto val : vec)
        if(val == data) ++count;
    return count;
}

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

في C# يمكنك تحقيق نفس الهدف باستخدام طريقة الامتداد:

static class Extensions {
    public static uint FindCount<T>(this List<T> list, T data) {
        uint counts = 0;
        foreach (var item in list)
            if (item.Equals(data)) ++counts;
        return counts;
    }
}

وكلاهما يعمل بنفس الطريقة وهو أمر رائع.سيجادل الكثيرون حول فقدان C++ لطرق الامتداد، وسيجادل الكثيرون حول فقدان وظائف مساحة الاسم في C#.

أعتقد أن أفضل طريقة لتوضيح الأمر هي عدم مقارنة هذه اللغات ببعض التفاصيل لأنها لغات مختلفة وتطبيقات مختلفة.

كما نقلت في سؤالك، C++/CLI لا يفعل ذلك "حقًا" يدعم وظائف أعضاء مساحة الاسم نظرًا لأنه يضيف فئة غير مسماة لاستخدامها والتي ليست قريبة بأي حال من الأحوال من تطبيق C++، وربما تكون قريبة من الطريقة التي تبدو بها، ولكنها مختلفة حقًا.

في النهاية، الوظيفة هي دائمًا شيء نتطلع إليه، وبقدر ما أريد وظائف أعضاء مساحة الاسم في C# بقدر ما أريد طرق الامتداد في C++.وهو ليس كثيرًا على أي حال.

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