used - user defined data types in c#




البث المباشر مقابل المشغل "كـ"؟ (10)

خذ بعين الاعتبار التعليمة البرمجية التالية:

void Handler(object o, EventArgs e)
{
   // I swear o is a string
   string s = (string)o; // 1
   //-OR-
   string s = o as string; // 2
   // -OR-
   string s = o.ToString(); // 3
}

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


  1. استخدام عندما يكون شيء ما بالتأكيد شيء آخر.
  2. استخدم عندما يكون هناك شيء آخر.
  3. استخدمه عندما لا تهتم بما هو عليه ولكنك تريد فقط استخدام تمثيل السلسلة المتاح.

"(السلسلة) o" سيؤدي إلى InvalidCastException حيث لا يوجد قالب مباشر.

"س كسلسلة" سيؤدي إلى أن تكون مرجعًا فارغًا ، بدلاً من أن يتم طرح استثناء.

"o.ToString ()" ليس مصفوفة من أي نوع في حد ذاته ، إنها طريقة يتم تنفيذها بواسطة الكائن ، وبالتالي بطريقة أو بأخرى ، من خلال كل فئة في .net التي "تقوم بشيء" مع مثيل الفصل الذي يطلق عليه ويعيد سلسلة.

لا تنسَ أنه بالنسبة للتحويل إلى سلسلة ، هناك أيضًا Convert.ToString (someType instanceOfThatType) حيث يكون someType واحدًا من مجموعة من الأنواع ، أساسًا أنواع القواعد الأساسية.


إذا كنت تعرف بالفعل نوع الكتابة التي يمكنه الإرسال إليها ، فاستخدم نمط C-cast:

var o = (string) iKnowThisIsAString; 

لاحظ أنه فقط مع نمط C-cast يمكنك تنفيذ إجبار نوع صريح.

إذا كنت لا تعرف ما إذا كان هذا هو النوع المرغوب وكنت ستستخدمه إذا كان كذلك ، فاستخدم ككلمة رئيسية:

var s = o as string;
if (s != null) return s.Replace("_","-");

//or for early return:
if (s==null) return;

لاحظ أنه لن يستدعي أي نوع من مشغلي التحويل. ستكون غير خالية إذا كان الكائن غير فارغ أو أصلي من النوع المحدد.

استخدم ToString () للحصول على تمثيل سلسلة يمكن لأي شخص أن يقرأه ، حتى إذا كان لا يمكن إرساله إلى سلسلة.


استخدم string s = (string) o; الإرسال المباشر string s = (string) o; إذا كان في السياق المنطقي string تطبيقك النوع الوحيد الصحيح. باستخدام هذا الأسلوب ، ستحصل على InvalidCastException وتطبيق مبدأ Fail-fast . ستتم حماية المنطق الخاص بك من تمرير نوع غير صحيح أو الحصول على NullReferenceException إذا تم استخدامه كمشغل.

إذا كان المنطق يتوقع عدة أنواع مختلفة ، فقم string s = o as string; وتحقق من ذلك على null أو الاستخدام is المشغل.

ظهرت ميزة جديدة رائعة في C # 7.0 لتبسيط الصب والتحقق هو مطابقة نمط :

if(o is string s)
{
  // Use string variable s
}

or

switch (o)
{
  case int i:
     // Use int variable i
     break;
  case string s:
     // Use string variable s
     break;
 }

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

(string)o.ToLower(); // won't compile

يمكنك فقط الكتابة:

((string)o).ToLower();

لكن يمكنك الكتابة بدلاً من ذلك:

(o as string).ToLower();

كخيار أكثر قابلية للقراءة (على الأقل إلى رأيي).


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

String s = String.Concat(o);

وفقًا للتجارب التي يتم تشغيلها في هذه الصفحة: http://www.dotnetguru2.org/sebastienros/index.php/2006/02/24/cast_vs_as

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

الاستنتاج هو ، المشغل "كـ" عادة أسرع من المدلى بها. في بعض الأحيان بسرعة أكبر وأحيانًا بالكاد أسرع.

أنا الشيء peronsonally "كما" هو أيضا أكثر قابلية للقراءة.

لذا ، نظرًا لأنه أسرع و "أكثر أمانًا" (باستثناء الاستثناء) ، وربما أسهل في القراءة ، فإنني أوصي باستخدام "كـ" طوال الوقت.


يبدو أن الاثنين منهم مختلفان من الناحية المفاهيمية.

الصب المباشر

لا يجب أن تكون الأنواع مرتبطة بشكل صارم. يأتي في جميع أنواع النكهات.

  • مخصص صب صريح / صريح: عادة ما يتم إنشاء كائن جديد.
  • نوع القيمة ضمني: نسخ دون فقدان المعلومات.
  • Value Type Explicit: Copy and information may lost.
  • العلاقة بين IS-A: تغيير نوع المرجع ، وإلا تعرض الاستثناء.
  • نفس النوع: "الصب غير متكرر".

يبدو وكأنه سيتم تحويل الكائن إلى شيء آخر.

AS المشغل

أنواع لها علاقة مباشرة. كما في:

  • أنواع المرجع: علاقة IS-A الكائنات هي نفسها دائمًا ، فقط التغييرات المرجعية.
  • أنواع القيم: نسخ الملاكمة وأنواع nullable.

يبدو أنك ستتعامل مع الكائن بطريقة مختلفة.

عينات و IL

    class TypeA
    {
        public int value;
    }

    class TypeB
    {
        public int number;

        public static explicit operator TypeB(TypeA v)
        {
            return new TypeB() { number = v.value };
        }
    }

    class TypeC : TypeB { }
    interface IFoo { }
    class TypeD : TypeA, IFoo { }

    void Run()
    {
        TypeA customTypeA = new TypeD() { value = 10 };
        long longValue = long.MaxValue;
        int intValue = int.MaxValue;

        // Casting 
        TypeB typeB = (TypeB)customTypeA; // custom explicit casting -- IL:  call class ConsoleApp1.Program/TypeB ConsoleApp1.Program/TypeB::op_Explicit(class ConsoleApp1.Program/TypeA)
        IFoo foo = (IFoo)customTypeA; // is-a reference -- IL: castclass  ConsoleApp1.Program/IFoo

        int loseValue = (int)longValue; // explicit -- IL: conv.i4
        long dontLose = intValue; // implict -- IL: conv.i8

        // AS 
        int? wraps = intValue as int?; // nullable wrapper -- IL:  call instance void valuetype [System.Runtime]System.Nullable`1<int32>::.ctor(!0)
        object o1 = intValue as object; // box -- IL: box [System.Runtime]System.Int32
        TypeD d1 = customTypeA as TypeD; // reference conversion -- IL: isinst ConsoleApp1.Program/TypeD
        IFoo f1 = customTypeA as IFoo; // reference conversion -- IL: isinst ConsoleApp1.Program/IFoo

        //TypeC d = customTypeA as TypeC; // wouldn't compile
    }

يعتمد الأمر فعلاً على ما إذا كنت تعرف ما إذا كان o عبارة عن سلسلة وما تريد فعله به. إذا كان تعليقك يعني أنه حقا عبارة عن سلسلة ، فأنا أفضل أن أكون مستقيمة (string)o .

أكبر ميزة لاستخدام المجموعة المباشرة هي أنه عندما تفشل ، تحصل على InvalidCastException ، والذي يخبرك إلى حد كبير بالخطأ.

باستخدام المشغل ، إذا لم تكن السلسلة عبارة عن s ، يتم تعيين s إلى null ، وهو مفيد إذا كنت غير متأكد وتريد اختبار s :

string s = o as string;
if ( s == null )
{
    // well that's not good!
    gotoPlanB();
}

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

في الحالة الخاصة للتحويل إلى سلسلة ، يحتوي كل كائن على ToString ، لذلك قد يكون ToString الثالث على ما يرام إذا لم تكن فارغة وتعتقد أن أسلوب ToString قد يفعل ما تريد.


string s = (string)o; // 1

يلقي InvalidCastException إذا لم يكن o عبارة عن string . وإلا ، فيحدد o إلى s ، حتى إذا كانت قيمة o null .

string s = o as string; // 2

يعيّن قيمة s إذا لم تكن o عبارة عن string أو إذا كانت قيمة o null . لهذا السبب ، لا يمكنك استخدامه مع أنواع القيم (لا يمكن للعامل أبدًا إرجاع القيمة null في هذه الحالة). خلاف ذلك ، يعين o إلى s .

string s = o.ToString(); // 3

يتسبب في NullReferenceException إذا كانت o null . يعيّن ما o.ToString() إلى s ، بغض النظر عن نوع o .

استخدم 1 لمعظم التحويلات - إنها بسيطة ومباشرة. أميل إلى عدم استخدام 2 تقريبًا مطلقًا إذا كان هناك شيء غير صحيح ، عادةً ما أتوقع حدوث استثناء. لقد رأيت فقط حاجة إلى هذا النوع من الوظائف الخالية من الإرجاع مع المكتبات سيئة التصميم التي تستخدم رموز الأخطاء (على سبيل المثال ، return null = error ، بدلاً من استخدام استثناءات).

3 لا يلقي و هو مجرد وسيلة للاحتجاج. استخدمها عندما تحتاج إلى تمثيل سلسلة كائن غير سلسلة.





casting