[C#] ما هو نوع "الديناميكي" في C # 4.0 المستخدم؟


Answers

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

خذ على سبيل المثال.

إذا كان لديك كائن COM ، مثل كائن Word.Application ، وتريد فتح مستند ، فإن طريقة القيام بذلك تأتي مع ما لا يقل عن 15 معلمة ، معظمها اختيارية.

لاستدعاء هذه الطريقة ، ستحتاج إلى شيء من هذا القبيل (أنا أبسط ، هذه ليست الكود الفعلي):

object missing = System.Reflection.Missing.Value;
object fileName = "C:\\test.docx";
object readOnly = true;
wordApplication.Documents.Open(ref fileName, ref missing, ref readOnly,
    ref missing, ref missing, ref missing, ref missing, ref missing,
    ref missing, ref missing, ref missing, ref missing, ref missing,
    ref missing, ref missing);

لاحظ كل تلك الحجج؟ تحتاج إلى تمرير تلك منذ C # قبل الإصدار 4.0 لم يكن لديك فكرة من الحجج الاختيارية. في C # 4.0 ، أصبحت واجهات برمجة التطبيقات COM أسهل في العمل من خلال تقديم:

  1. الحجج الاختيارية
  2. جعل ref اختياريًا لواجهة برمجة تطبيقات COM
  3. الوسائط المسماة

سيكون بناء الجملة الجديد للمكالمة أعلاه:

wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);

انظر كم تبدو أسهل ، كم يصبح أكثر قابلية للقراءة؟

دعونا نكسر ذلك:

                                    named argument, can skip the rest
                                                   |
                                                   v
wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);
                                 ^                         ^
                                 |                         |
                               notice no ref keyword, can pass
                               actual parameter values instead

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

تنقسم الأشياء في C # قبل الإصدار 4.0 أكثر إذا حاولت التحدث إلى كائن COM ليس لديك واجهة أو فئة ، كل ما لديك هو مرجع IDispatch .

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

يمكن أن تبدو طريقة الحفظ أعلاه مثل هذا (وهذا بالتأكيد ليس الرمز الصحيح):

string[] methodNames = new[] { "Open" };
Guid IID = ...
int methodId = wordApplication.GetIDsOfNames(IID, methodNames, methodNames.Length, lcid, dispid);
SafeArray args = new SafeArray(new[] { fileName, missing, missing, .... });
wordApplication.Invoke(methodId, ... args, ...);

كل هذا فقط لفتح وثيقة.

كان لدى VB حججًا ودعمًا اختياريًا لمعظم هذا خارج المربع منذ وقت طويل ، لذلك رمز C # هذا:

wordApplication.Documents.Open(@"C:\Test.docx", ReadOnly: true);

هي في الأساس مجرد C # اللحاق تصل إلى VB من حيث التعبيرية ، ولكن تفعل ذلك بالطريقة الصحيحة ، من خلال جعلها قابلة للتمديد ، وليس فقط بالنسبة COM. بالطبع هذا متاح أيضًا لـ VB.NET أو أي لغة أخرى تم إنشاؤها في أعلى وقت تشغيل .NET.

يمكنك العثور على مزيد من المعلومات حول واجهة IDispatch على IDispatch إذا كنت ترغب في قراءة المزيد عنها. إنها حقا أشياء دموية

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

وعن روبي؟ واجهة برمجة تطبيقات مختلفة لا تزال.

جافا سكريبت؟ نفس الصفقة ، API مختلفة لذلك أيضا.

تتكون الكلمة الرئيسية الديناميكية من شيئين:

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

ومع ذلك ، لا تعني الكلمة الرئيسية dynamic استبدال أي كود .NET موجود فقط. بالتأكيد ، يمكنك فعل ذلك ، ولكن لم يتم إضافته لهذا السبب ، وكان مؤلفو لغة البرمجة C # مع Anders Hejlsberg في المقدمة ، الأكثر مصراً أنهم ما زالوا يعتبرون C # كلغة مكتوبة بقوة ، ولن يضحيوا هذا المبدأ.

هذا يعني أنه على الرغم من أنه يمكنك كتابة رمز مثل هذا:

dynamic x = 10;
dynamic y = 3.14;
dynamic z = "test";
dynamic k = true;
dynamic l = x + y * z - k;

وتجميعها ، لم يكن المقصود بها نوعًا من نوع النظام السحري الذي يتيح لك الوصول إلى وقت التشغيل.

كان الغرض كله هو تسهيل التحدث إلى أنواع أخرى من الكائنات.

هناك الكثير من المواد على الإنترنت حول الكلمة الرئيسية ، المؤيدين ، المعارضين ، المناقشات ، التشدقات ، الثناء ، إلخ.

أقترح أن تبدأ بالروابط التالية ومن ثم google للحصول على المزيد:

Question

قدم C # 4.0 نوع جديد يسمى "ديناميكية". يبدو كل شيء جيدًا ، ولكن ماذا يستخدمه المبرمج؟

هل هناك وضع حيث يمكن أن ينقذ اليوم؟




فهو يجعل من السهل على اللغات الثابتة المكتوبة (CLR) أن تتفاعل مع اللغات الديناميكية (python، ruby ​​...) التي تعمل على DLR (وقت تشغيل اللغة الديناميكي) ، انظر MSDN .




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

public static dynamic GetSomeData(ParameterDTO dto)
        {
            dynamic result = null;
            string SPName = "a_legacy_stored_procedure";
            using (SqlConnection connection = new SqlConnection(DataConnection.ConnectionString))
            {
                SqlCommand command = new SqlCommand(SPName, connection);
                command.CommandType = System.Data.CommandType.StoredProcedure;                
                command.Parameters.Add(new SqlParameter("@empid", dto.EmpID));
                command.Parameters.Add(new SqlParameter("@deptid", dto.DeptID));
                connection.Open();
                using (SqlDataReader reader = command.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        dynamic row = new ExpandoObject();
                        row.EmpName = reader["EmpFullName"].ToString();
                        row.DeptName = reader["DeptName"].ToString();
                        row.AnotherColumn = reader["AnotherColumn"].ToString();                        
                        result = row;
                    }
                }
            }
            return result;
        }



  1. يمكنك الاتصال باللغات الديناميكية مثل CPython باستخدام pythonnet:

dynamic np = Py.Import("numpy")

  1. يمكنك طرح الأدوية البديلة dynamic عند تطبيق المشغلين الرقميين عليها. وهذا يوفر سلامة النوع ويتجنب قيود الأدوية الجنسية. هذا هو في جوهر * كتابة بطة:

T y = x * (dynamic)x ، حيث typeof(x) is T




مثال على الاستخدام:

تستهلك العديد من الفئات التي تحتوي على خاصية مشتركة "CreationDate":

public class Contact
{
    // some properties

    public DateTime CreationDate { get; set; }        
}

public class Company
{
    // some properties

    public DateTime CreationDate { get; set; }

}

public class Opportunity
{
    // some properties

    public DateTime CreationDate { get; set; }

}

إذا كتبت طريقة مشتركة تسترد قيمة خاصية 'CreationDate' ، فسيتعين عليك استخدام التفكير:

    static DateTime RetrieveValueOfCreationDate(Object item)
    {
        return (DateTime)item.GetType().GetProperty("CreationDate").GetValue(item);
    }

باستخدام مفهوم "الديناميكي" ، يصبح رمزك أكثر أناقة:

    static DateTime RetrieveValueOfCreationDate(dynamic item)
    {
        return item.CreationDate;
    }