سؤال

القسم 6.1 تحويلات ضمنية يحدد تحويل الهوية وبالتالي:

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

الآن ، ما هو الغرض من الجمل مثل هذه؟

(في الفقرة 6.1.6 تحويلات مرجعية ضمنية)

التحويلات المرجعية الضمنية هي:

  • [...]
  • من أي واحدة نوع مرجع إلى نوع مرجع T إذا كان لديه هوية ضمنية أو تحويل مرجعي إلى أ نوع مرجع T0 و T0 لديه تحويل الهوية إلى T.

و:

(في §6.1.7 تحويلات الملاكمة)

  • يحتوي نوع القيمة على تحويل الملاكمة إلى نوع واجهة I إذا كان لديه تحويل الملاكمة إلى نوع واجهة I0 و I0 لديه تحويل الهوية إلى I.

في البداية تبدو زائدة عن الحاجة (tautologous). لكن يجب أن يكونوا هناك لغرض ما ، فلماذا هم هناك؟

هل يمكنك إعطاء مثال لنوعين T1, T2 مثل ذلك T1 سيكون ليس تكون قابلة للتحويل ضمنيًا إلى T2 إذا لم تكن الفقرات المذكورة أعلاه؟

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

المحلول

يشير القسم 4.7 من المواصفات إلى وجود تحويل هوية من Foo<dynamic> إلى Foo<object> والعكس صحيح. يتم كتابة جزء المواصفات التي نقلتها للتأكد من معالجة هذه القضية. أي إذا كان هناك تحويل مرجعي ضمني من t إلى C<object, object> ثم هناك أيضًا تحويل مرجعي ضمني إلى C<object, dynamic>, C<dynamic, object> و C<dynamic, dynamic>.

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

المواصفات ، للأسف ، ليست وثيقة مثالية.

نصائح أخرى

تحديث في 22 سبتمبر 2010:

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


تحديث في 19 سبتمبر 2010:

في تعليقك:

t] له لا معنى له.

لعنة ، تيموي ، أنت تقول ذلك كثيراً. ولكن حسنًا ، إذن ؛ لقد وضعتني على الدفاع ، لذلك هنا يذهب!

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

أماكن مختلفة

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

ردك ، ومع ذلك ، كان على يكرر فرضيتك: "إذا كانت الجمل زائدة عن الحاجة حقًا ، فإنها تخلط بين القارئ فقط ولا توضح أي شيء."

(أحب الطريقة التي تضع بها نفسك كممثل لجميع قراء المواصفات هناك ، بالمناسبة.)

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

الغرض من تحويل الهوية تعريف

للوهلة الأولى ، يبدو هذا التعريف غير ضروري إلى حد ما ؛ أليس فقط يقول أن مثيلًا من أي نوع T قابل للتحويل إلى ... حسنًا ، إلى T؟ نعم إنه كذلك. لكنني افترض* أن الغرض من هذا التعريف هو تزويد المواصفات بالمفردات المناسبة لاستخدام مفهوم اكتب الهوية في سياق المناقشة التحويلات.

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

لكن مرة أخرى: تحويل الهوية التعريف موجود في المقام الأول لتجهيز المواصفات بلغة رسمية لوصف التحويلات دون الحاجة إلى قول أشياء مثل "إذا t0 و T هي حقا نفس النوع. "

حسنًا ، حان الوقت لأمثلة ملموسة.

حيث وجود تحويل ضمني قد لا يكون واضحا ل بعض المطورين

ملاحظة: أ أفضل بكثير تم تقديم مثال من قبل إريك ليبرت في إجابته على السؤال. أترك هذين المثالين الأولين كتعزيزات بسيطة فقط في وجهة نظري. لقد أضفت أيضًا مثالًا ثالثًا يلفت تحويل الهوية الموجود بين object و dynamic كما أشار في إجابة إريك.

تحويل مرجعي متعدية

لنفترض أن لديك نوعين ، M و N, ، ولديك تحويل ضمني محدد مثل هذا:

public static implicit operator M(N n);

ثم يمكنك كتابة رمز مثل هذا:

N n = new N();
M m = n;

الآن دعنا نقول أنك حصلت على ملف بهذا using بيان أعلى:

using K = M;

ثم لديك ، لاحقًا في الملف:

N n = new N();
K k = n;

حسنًا ، قبل أن أتابع ، أدرك ذلك هذا واضح ل أنت و أنا. لكن إجابتي هي ، وقد كانت منذ البداية ليس كن واضحا كل واحد, وبالتالي تحديد ذلك-في حين متكرر-لا داعي له غاية.

الذي - التي غاية هو: لتوضيح أي شخص يخدش رأسه ، والنظر إلى هذا الرمز ، إنه قانوني. و تحويل ضمني موجود من n إلى m ، و تحويل الهوية موجود من M إلى K (أي ، M و K هما نفس النوع) ؛ لذلك هناك تحويل ضمني من n إلى K. ليس الأمر كذلك فقط منطقي (على الرغم من أنه قد يكون يكون منطقي) ؛ إنه موجود في المواصفات. وإلا فقد يعتقد المرء عن طريق الخطأ أن شيئًا مثل ما يلي سيكون ضروريًا:

K k = (M)n;

بوضوح ، ليس كذلك.

تحويل الملاكمة متعدية

أو خذ النوع int. و int يمكن أن يكون محاصرًا ك IComparable<int>, ، حقا؟ لذلك هذا قانوني:

int i = 10;
IComparable<int> x = i;

الآن فكر في هذا:

int i = 10;
IComparable<System.Int32> x = i;

ثانية، نعم, ، من الممكن ان تكون بديهي بالنسبة لك ، أنا ، و 90 ٪ من جميع المطورين الذين قد يصادفونها. لكن لتلك الأقلية النحيفة التي لا تراها على الفور: أ تحويل الملاكمة موجود من int إلى IComparable<int>, ، و تحويل الهوية موجود من IComparable<int> إلى IComparable<System.Int32> (بمعنى آخر، IComparable<int> و IComparable<System.Int32> هي نفس النوع) ؛ لذلك يوجد تحويل الملاكمة من int إلى IComparable<System.Int32>.

التحويل الذي ينطوي على dynamic يكتب

سأقوم بالاقتراض من مثال التحويل المرجعي أعلاه وأقوم بتعديله قليلاً لتوضيح علاقة الهوية بين object و dynamic في الإصدار 4.0 من المواصفات.

دعنا نقول أن لدينا الأنواع M<T> و N, وقد حددت في مكان ما التحويل الضمني التالي:

public static implicit operator M<object>(N n);

ثم ما يلي قانوني:

N n = new N();
M<dynamic> m = n;

من الواضح أن ما سبق أقل بكثير بديهي من مثالين سابقين. ولكن هذا هو السؤال المليون دولار: سوف أعلاه ساكن كن قانونيًا حتى لو لم تكن مقتطفات من المواصفات المقتبسة في السؤال لم تكن موجودة؟ (سأتصل بهذه مقتطفات س للإيجاز.) إذا كانت الإجابة نعم ، إذن س هو في الواقع زائدة عن الحاجة. إذا كان لا ، فهذا ليس كذلك.

أعتقد أن الجواب هو نعم.

النظر في تعريف تحويل الهوية, ، المحددة في القسم 6.1.1 (أنا بما في ذلك القسم بأكمله هنا لأنه قصير جدًا):

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

لان object و dynamic تعتبر مكافئة هناك تحويل هوية بين object و dynamic, وبين الأنواع التي تم بناؤها هي نفسها عند استبدال جميع حالات dynamic مع object. التأكيد لي

(تم تضمين هذا الجزء الأخير أيضًا في القسم 4.7 ، والذي يحدد dynamic يكتب.)

الآن دعونا نلقي نظرة على الكود مرة أخرى. على وجه الخصوص أنا مهتم بهذا السطر الواحد:

M<dynamic> m = n;

شرعية هذا البيان (تجاهل س - تذكر أن القضية التي تتم مناقشتها هي الشرعية الافتراضية للبيان أعلاه إذا س فعلت ليس موجود) منذ ذلك الحين M<T> و N هي أنواع مخصصة ، تعتمد على وجود تحويل ضمني محدد من قبل المستخدم بين N و M<dynamic>.

يوجد تحويل ضمني من N إلى M<object>. من خلال قسم المواصفات المذكورة أعلاه ، هناك تحويل هوية بين M<object> و M<dynamic>. من خلال تعريف تحويل الهوية, M<object> و M<dynamic> هي نفس النوع.

لذلك ، كما هو الحال في أول مثالين (أكثر وضوحًا) ، أعتقد أنه من الصحيح وجود تحويل ضمني من N إلى M<dynamic> حتى دون أخذ س داخل الحساب, ، كما هو صحيح أن هناك تحويل ضمني من N إلى K في المثال الأول ووجود تحويل الملاكمة من int إلى IComparable<System.Int32> في المثال الثاني.

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

استنتاج

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

هل يمكنك إعطاء مثال لنوعين ر1, ، ر2 هذا ر1 لن تكون قابلة للتحويل ضمنيًا إلى ر2 إذا لم تكن الفقرات المذكورة أعلاه؟

لا أحد سيواجه هذا التحدي ، تيموي ، لأنه مستحيل. خذ المقتطف الأول حول التحويلات المرجعية. إنه يقول أن النوع K قابل للتحويل ضمنيًا إلى نوع T إذا كان قابلاً للتحويل ضمنيًا إلى t0 و ت0 هل هو نفسه T. تفكيك هذا ، ووضعه مرة أخرى معًا ، وتركت مع tautology واضحة: K قابلة للتحويل ضمنيًا إلى T إذا كان قابلاً للتحويل ضمنيًا إلى T. هل هذا يقدم أي تحويلات ضمنية جديدة؟ بالطبع لا.

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

متكرر؟ نعم. tautologous؟ نعم. بلا هدف؟ في لي الرأي ، لا.

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


الإجابة الأصلية

أعتقد أنك (ربما عن قصد) تطل على الإجابة الأكثر وضوحًا هنا.

النظر في هاتين الجملتين في سؤالك:

(1) في البداية تبدو زائدة عن الحاجة (tautologous). (2) لكن يجب أن يكونوا هناك لغرض ما ، فلماذا هم هناك؟

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

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

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

لذلك: نعم ، ربما تكون زائدة عن الحاجة. لكن هذا لا ينفي هدفهم.

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

هذا يقول أنه في C#-land ، 1 == 1 ؛ الأشياء بأسمائها الحقيقية. هذا هو أساس تعيين مرجع كائن إلى متغير من نفس النوع ؛ إذا كان هناك T1 المتغير الذي كتبه T1 وواحد من T2 المكتوبة في الواقع كلا البستونيين ، فمن الممكن تعيين واحد للآخر دون الحاجة إلى إلقاء واحد بشكل صريح كأسمال. تخيل أن البديل C# حيث كان على المهام أن تبدو هكذا:

Spade mySpade = new Spade();
Spade mySpade2;

mySpade2 = (Spade)mySpade; //explicit cast required

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

public int myMethod() { /*Do something*/ }
...
int myInt = (int)myMethod(); //required even though myMethod() evals to an int.
...
int myInt = (int)(1 + 2); //required even though 1, 2, and 1+2 eval to an int.

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

public class MyClass
{
  Int32 MyBoxedValueType; //using "int" not legal
}

...

MyClass myClass = new MyClass();
int theInt = 2;

myClass.MyBoxedValueType = (Int32)theInt; //explicit cast required

أعلم أن الأمر يبدو سخيفًا ، ولكن على مستوى ما ، يجب أن تكون هذه الأشياء معروفة ، وفي أجهزة الكمبيوتر ، يجب عليك تحديد كل شيء. اقرأ كتاب قواعد الهوكي في الولايات المتحدة الأمريكية للهوكي الجليدي في وقت ما ؛ القاعدة الأولى في الكتاب هي أن اللعبة ستلعب على سطح الجليد. إنها واحدة من "Duhs" في نهاية المطاف ، ولكن أيضًا حقيقة أساسية للعبة يجب فهمها من أجل أن يكون لأي قاعدة أخرى منطقية.

قد يكون هذا الرمز يضمن النجاح عند استدعائه Convert.ChangeType(client, typeof(Client)) بغض النظر إذا IConvertible تم تنفيذه.

انظر إلى مصدر ChangeType من mscorlib مع العاكس ولاحظ الشروط التي value عاد كما هو.

تذكر أ = المشغل ليس تحويل ، مجرد مجموعة مرجعية. حتى رمز مثل Client client_2 = client_1 لا يؤدي أي تحويلات ضمنية. إذا تم الإعلان عن تحويل هوية ضمني CS0555 صدر.

أعتقد أن المواصفات تقول دع المترجم C# يتعامل مع مثل هذه الحالات ، وبالتالي نقطة لا حاول يدويًا تحديد تحويلات الهوية.

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