سؤال

هل لدى C# خصائص تمديد؟

على سبيل المثال ، هل يمكنني إضافة خاصية تمديد إلى DateTimeFormatInfo اتصل ShortDateLongTimeFormat التي ستعود ShortDatePattern + " " + LongTimePattern?

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

المحلول

لا ، فهي غير موجودة في C# 3.0 ولن تتم إضافتها في 4.0. إنه مدرج في قائمة رغبات الميزات لـ C# ، لذا يمكن إضافتها في تاريخ مستقبلي.

في هذه المرحلة ، أفضل ما يمكنك فعله هو طرق تمديد نمط Getxxx.

نصائح أخرى

لا ، فهي غير موجودة.

أعلم أن فريق C# كان يفكر فيها في وقت واحد (أو على الأقل كان إريك ليبرت) - إلى جانب مُنشئو التمديد والمشغلين (قد يستغرق الأمر بعض الوقت للحصول على رأسك ، لكنهم رائعون ...) ومع ذلك ، فأنا لم أكن أتعامل معها لقد رأيت أي دليل على أنهم سيكونون جزءًا من C# 4.

تحرير: لم تظهر في C# 5 ، واعتبارًا من يوليو 2014 ، لا يبدو أنه سيكون في C# 6 أيضًا.

إريك ليبرت, ، المطور الرئيسي في فريق برنامج التحويل البرمجي C في Microsoft من خلال نوفمبر 2012 ، تدوين حول هذا الموضوع في أكتوبر 2009:

في الوقت الحالي ، لا يزال غير مدعوم خارج الصندوق بواسطة برنامج التحويل البرمجي Roslyn ...

حتى الآن ، لم يُنظر إلى خصائص التمديد على أنها قيمة بما يكفي لإدراجها في الإصدارات السابقة من C# Standard. ج# 7 و ج# 8.0 لقد رأيت هذا كبطل اقتراح ، لكن لم يتم إصداره بعد ، والأهم من ذلك كله لأنه حتى لو كان هناك بالفعل تنفيذ ، فإنهم يريدون أن يصنعوا ذلك منذ البداية.

لكنه سيبقى ...

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

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

علاوة على ذلك ، يمكنك استخدام حل بديل

كما هو محدد في هذا مقالة - سلعة, ، يمكنك استخدام ال TypeDescriptor القدرة على إرفاق سمة على مثيل كائن في وقت التشغيل. ومع ذلك ، فهو لا يستخدم بناء جملة الخصائص القياسية.
إنه مختلف قليلاً عن مجرد سكر النحوي مما يضيف إمكانية لتحديد خاصية ممتدة مثل
string Data(this MyClass instance) كمستعار لطريقة التمديد
string GetData(this MyClass instance) لأنه يخزن البيانات في الفصل.

آمل أن يوفر C#7 امتدادًا مميزًا بالكامل (خصائص وحقول) ، ولكن في هذه النقطة ، سيحدد الوقت فقط.

لا تتردد في المساهمة لأن برنامج الغد سيأتي من المجتمع.

تحديث: أغسطس 2016

كما نشر فريق dotnet ما الجديد في C# 7.0 ومن تعليق Mads Torgensen:

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

يبدو أن خصائص التمديد والأعضاء الآخرين ، لا تزال مرشحين جيدين ليتم تضمينهم في إصدار مستقبلي من Roslyn ، ولكن ربما ليس 7.0 واحد.

تحديث: مايو 2017

أعضاء التمديد تم إغلاقه كنسخ من تمديد كل شيء مشكلة وهو مغلق أيضًا. كانت المناقشة الرئيسية في الواقع حول نوع التوسع بالمعنى الواسع. تم تتبع الميزة الآن هنا كاقتراح وقد تمت إزالته من 7.0 معلم.

تحديث: أغسطس ، 2017 - الميزة C# 8.0 المقترحة

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

public interface IEmployee 
{
    public decimal Salary { get; set; }
}

public class Employee
{
    public decimal Salary { get; set; }
}

public extension MyPersonExtension extends Person : IEmployee
{
    private static readonly ConditionalWeakTable<Person, Employee> _employees = 
        new ConditionalWeakTable<Person, Employee>();


    public decimal Salary
    {
        get 
        {
            // `this` is the instance of Person
            return _employees.GetOrCreate(this).Salary; 
        }
        set 
        {
            Employee employee = null;
            if (!_employees.TryGetValue(this, out employee)
            {
                employee = _employees.GetOrCreate(this);
            }
            employee.Salary = value;
        }
    }
}

IEmployee person = new Person();
var salary = person.Salary;

على غرار الفئات الجزئية ، ولكن تم تجميعها كفئة/نوع منفصل في مجموعة مختلفة. لاحظ أنك ستتمكن أيضًا من إضافة أعضاء ومشغلين ثابتين بهذه الطريقة. كما ذكر في Mads Torgensen Podcast, لن يحتوي الامتداد على أي حالة (لذلك لا يمكن إضافة أعضاء مثيل خاص إلى الفصل) مما يعني أنك لن تتمكن من إضافة بيانات مثيل خاصة مرتبطة بالمثال. السبب الذي تم استدعاؤه لهذا هو أنه يعني إدارة القواميس الداخلية وقد يكون الأمر صعبًا (إدارة الذاكرة ، إلخ ...). لهذا ، لا يزال بإمكانك استخدام TypeDescriptor/ConditionalWeakTable تقنية موصوفة سابقًا ومع امتداد العقار ، تخفيها تحت خاصية لطيفة.

بناء الجملة لا يزال عرضة للتغيير كما يعني هذا القضية. فمثلا، extends يمكن استبداله for الذي قد يشعر البعض أكثر طبيعية وأقل ذات صلة جافا.

تحديث ديسمبر 2018 - الأدوار والتمديدات وأعضاء الواجهة الثابتة

تمديد كل شيء لم تصل إلى C# 8.0 ، بسبب بعض العيوب الموضحة على أنها نهاية هذا تذكرة جيثب. لذلك ، كان هناك استكشاف لتحسين التصميم. هنا, ، يشرح Mads Torgensen ما هو الأدوار والإضافات وكيف تختلف:

تسمح الأدوار بتنفيذ الواجهات على قيم محددة من نوع معين. تتيح الامتدادات تنفيذ الواجهات على جميع قيم نوع معين ، داخل منطقة محددة من التعليمات البرمجية.

يمكن رؤيته في تقسيم الاقتراح السابق في حالتين للاستخدام. ال بناء جملة جديد للتمديد سيكون هكذا:

public extension ULongEnumerable of ulong
{
    public IEnumerator<byte> GetEnumerator()
    {
        for (int i = sizeof(ulong); i > 0; i--)
        {
            yield return unchecked((byte)(this >> (i-1)*8));
        }
    }
}

ثم ستتمكن من القيام بذلك:

foreach (byte b in 0x_3A_9E_F1_C5_DA_F7_30_16ul)
{
    WriteLine($"{e.Current:X}");
}

ولل واجهة ثابتة:

public interface IMonoid<T> where T : IMonoid<T>
{
    static T operator +(T t1, T t2);
    static T Zero { get; }
}

إضافة خاصية التمديد على int وعلاج int كما IMonoid<int>:

public extension IntMonoid of int : IMonoid<int>
{
    public static int Zero => 0;
}

تحديث (بفضل chaost لتوجيه هذا التحديث):

مادس تورجرسن: "امتداد كل شيء لم يصل إلى C# 8.0. لقد تم" القبض عليه "، إذا صح التعبير ، في نقاش مثير للغاية حول المستقبل الإضافي للغة ، والآن نريد التأكد من أننا لا نضيفها الطريقة التي تمنع تلك الاحتمالات المستقبلية. في بعض الأحيان يكون تصميم اللغة لعبة طويلة جدًا! "

مصدر: قسم التعليقات في https://blogs.msdn.microsoft.com/dotnet/2018/11/12/building-c-8-0/


توقفت عن حساب عدد المرات على مر السنين التي فتحت فيها هذا السؤال على أمل رؤية هذا المطبق.

حسنًا ، أخيرًا يمكننا أن نفرح! ستقدم Microsoft هذا في إصدار C# 8 القادم.

لذا بدلاً من القيام بذلك ...

public static class IntExtensions
{
   public static bool Even(this int value)
   {
        return value % 2 == 0;
   }
}

سنكون قادرين أخيرًا على القيام بذلك مثل ...

public extension IntExtension extends int
{
    public bool Even => this % 2 == 0;
}

مصدر: https://blog.ndepend.com/c-8-0-features-glimpse-future/

كما ذكر psyonity ، يمكنك استخدام شرطية weachtable لإضافة خصائص إلى الكائنات الموجودة. بالاقتران مع توسيع Dynamic ، يمكنك تنفيذ خصائص التمديد الديناميكية في بضعة أسطر:

using System.Dynamic;
using System.Runtime.CompilerServices;

namespace ExtensionProperties
{
    /// <summary>
    /// Dynamically associates properies to a random object instance
    /// </summary>
    /// <example>
    /// var jan = new Person("Jan");
    ///
    /// jan.Age = 24; // regular property of the person object;
    /// jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;
    ///
    /// if (jan.Age &lt; jan.DynamicProperties().NumberOfDrinkingBuddies)
    /// Console.WriteLine("Jan drinks too much");
    /// </example>
    /// <remarks>
    /// If you get 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create' you should reference Microsoft.CSharp
    /// </remarks>
    public static class ObjectExtensions
    {
        ///<summary>Stores extended data for objects</summary>
        private static ConditionalWeakTable<object, object> extendedData = new ConditionalWeakTable<object, object>();

        /// <summary>
        /// Gets a dynamic collection of properties associated with an object instance,
        /// with a lifetime scoped to the lifetime of the object
        /// </summary>
        /// <param name="obj">The object the properties are associated with</param>
        /// <returns>A dynamic collection of properties associated with an object instance.</returns>
        public static dynamic DynamicProperties(this object obj) => extendedData.GetValue(obj, _ => new ExpandoObject());
    }
}

مثال على الاستخدام في تعليقات XML:

var jan = new Person("Jan");

jan.Age = 24; // regular property of the person object;
jan.DynamicProperties().NumberOfDrinkingBuddies = 27; // not originally scoped to the person object;

if (jan.Age < jan.DynamicProperties().NumberOfDrinkingBuddies)
{
    Console.WriteLine("Jan drinks too much");
}

jan = null; // NumberOfDrinkingBuddies will also be erased during garbage collection

لأنني كنت بحاجة مؤخرًا ، نظرت إلى مصدر الإجابة في:

C# تمديد الفصل عن طريق إضافة خصائص

وخلق نسخة أكثر ديناميكية:

public static class ObjectExtenders
{
    static readonly ConditionalWeakTable<object, List<stringObject>> Flags = new ConditionalWeakTable<object, List<stringObject>>();

    public static string GetFlags(this object objectItem, string key)
    {
        return Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value;
    }

    public static void SetFlags(this object objectItem, string key, string value)
    {
        if (Flags.GetOrCreateValue(objectItem).Any(x => x.Key == key))
        {
            Flags.GetOrCreateValue(objectItem).Single(x => x.Key == key).Value = value;
        }
        else
        {
            Flags.GetOrCreateValue(objectItem).Add(new stringObject()
            {
                Key = key,
                Value = value
            });
        }
    }

    class stringObject
    {
        public string Key;
        public string Value;
    }
}

من المحتمل أن يتم تحسينه كثيرًا (التسمية ، ديناميكية بدلاً من السلسلة) ، أستخدم هذا حاليًا في CF 3.5 جنبًاhttps://gist.github.com/jan-willemdebruyn/db79dd6fdef7b9845e217958db98c4d4)

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