সিএলআরতে 'হিসাবে' কীওয়ার্ড ব্যবহার করে বনাম Castালাই করা


386

ইন্টারফেস প্রোগ্রামিং করার সময়, আমি অনেক কাস্টিং বা অবজেক্টের ধরণের রূপান্তরটি করেছি।

এই দুটি রূপান্তর পদ্ধতির মধ্যে পার্থক্য আছে কি? যদি তা হয় তবে কোনও ব্যয়ের পার্থক্য রয়েছে বা কীভাবে এটি আমার প্রোগ্রামকে প্রভাবিত করে?

public interface IMyInterface
{
    void AMethod();
}

public class MyClass : IMyInterface
{
    public void AMethod()
    {
       //Do work
    }

    // Other helper methods....
}

public class Implementation
{
    IMyInterface _MyObj;
    MyClass _myCls1;
    MyClass _myCls2;

    public Implementation()
    {
        _MyObj = new MyClass();

        // What is the difference here:
        _myCls1 = (MyClass)_MyObj;
        _myCls2 = (_MyObj as MyClass);
    }
}

এছাড়াও, "সাধারণভাবে" পছন্দের পদ্ধতিটি কী?


আপনি কেন প্রথম স্থানে কাস্ট ব্যবহার করছেন এই প্রশ্নের একটি ছোট্ট উদাহরণ যোগ করতে পারেন, বা একটি নতুন শুরু করতে পারেন? আমি শুধু ইউনিট পরীক্ষার জন্য আপনার অভিনেতার কেন প্রয়োজন তা আগ্রহী। আমি মনে করি এটি যদিও এই প্রশ্নের ক্ষেত্রের বাইরে।
এরিক ভ্যান ব্রাকেল

2
এর প্রয়োজনীয়তা রোধ করতে আমি সম্ভবত আমার ইউনিট পরীক্ষাটি পরিবর্তন করতে পারি। মূলত এটি এ সম্পর্কে ফোটে যে আমার কংক্রিট অবজেক্টে আমার একটি সম্পত্তি রয়েছে যা ইন্টারফেসে নেই। আমার সেই সম্পত্তিটি সেট করা দরকার তবে বাস্তব জীবন সেই সম্পত্তি অন্য উপায়ে সেট করা হত। এতে আপনার প্রশ্নের উত্তর হলো কি?
ফ্র্যাঙ্ক ভি

Patrik Hägne বলেছ নীচে তুলে ধরা বিষয় চিহ্নিত করেছে, সেখানে IS একটি পার্থক্য।
নীল

উত্তর:


517

লাইনের নীচে উত্তরটি ২০০৮ সালে লেখা হয়েছিল।

সি # 7 প্রবর্তিত প্যাটার্ন ম্যাচিং, যা asঅপারেটরটিকে ব্যাপকভাবে প্রতিস্থাপন করেছে , আপনি এখন যেমন লিখতে পারেন:

if (randomObject is TargetType tt)
{
    // Use tt here
}

মনে রাখবেন যে ttএটির পরেও সুযোগ রয়েছে, তবে অবশ্যই নির্ধারিত নয়। (এটা হয় স্পষ্টভাবে মধ্যে নির্ধারিত ifশরীর।) কিছু ক্ষেত্রে সামান্য বিরক্তিকর, তাই আপনি যদি সত্যিই যে সুযোগ সম্ভাব্য ভেরিয়েবল সবচেয়ে ছোট সংখ্যা প্রবর্তনের যত্নশীল, আপনি কি এখনও ব্যবহার করতে চাইতে পারেন isএকটি ঢালাই করে।


আমার মনে হয় না এ পর্যন্ত যে কোনও উত্তর (উত্তরটি শুরু করার সময়!) সত্যই ব্যাখ্যা করেছে যে এটি কোনটি ব্যবহার করার পক্ষে উপযুক্ত।

  • এটি করবেন না:

    // Bad code - checks type twice for no reason
    if (randomObject is TargetType)
    {
        TargetType foo = (TargetType) randomObject;
        // Do something with foo
    }

    এটি কেবল দুটিবার যাচাই করা নয়, এটি randomObjectস্থানীয় ভেরিয়েবলের চেয়ে ক্ষেত্র যদি হয় তবে এটি বিভিন্ন জিনিসও চেক করতে পারে । "যদি" পাস করা সম্ভব হয় তবে কাস্ট ব্যর্থ হতে পারে, যদি অন্য থ্রেডের randomObjectমধ্যে দুটির মান পরিবর্তন হয় ।

  • যদি randomObjectসত্যিই উদাহরণস্বরূপ হওয়া উচিতTargetType , যদি তা না হয় তবে এর অর্থ একটি বাগ রয়েছে, তবে castালাই সঠিক সমাধান। এটি অবিলম্বে একটি ব্যতিক্রম ছোঁড়ে, যার অর্থ ভুল অনুমানের অধীনে আর কোনও কাজ করা হয় না এবং ব্যতিক্রমটি সঠিকভাবে বাগের ধরণটি দেখায়।

    // This will throw an exception if randomObject is non-null and
    // refers to an object of an incompatible type. The cast is
    // the best code if that's the behaviour you want.
    TargetType convertedRandomObject = (TargetType) randomObject;
  • যদি এটির উদাহরণ randomObject হতে পারে TargetTypeএবং TargetTypeএকটি রেফারেন্স টাইপ হয়, তবে এই জাতীয় কোড ব্যবহার করুন:

    TargetType convertedRandomObject = randomObject as TargetType;
    if (convertedRandomObject != null)
    {
        // Do stuff with convertedRandomObject
    }
  • যদি এটির উদাহরণ randomObject হতে পারে TargetTypeএবং TargetTypeমান ধরণের হয় তবে আমরা নিজের asসাথে এটি ব্যবহার করতে পারি না TargetType, তবে আমরা একটি প্রচ্ছন্ন প্রকারটি ব্যবহার করতে পারি:

    TargetType? convertedRandomObject = randomObject as TargetType?;
    if (convertedRandomObject != null)
    {
        // Do stuff with convertedRandomObject.Value
    }

    (দ্রষ্টব্য: বর্তমানে এটি + কাস্টের চেয়ে আসলে ধীর গতিযুক্ত I আমি মনে করি এটি আরও মার্জিত এবং ধারাবাহিক, তবে আমরা সেখানে যাই))

  • আপনি কি সত্যিই রূপান্তরিত মান প্রয়োজন না থাকে, তাহলে কিন্তু আপনি শুধু জানতে কিনা এটা প্রয়োজন হয় TargetType একটি দৃষ্টান্ত, তারপর isঅপারেটর আপনার বন্ধু। এই ক্ষেত্রে টার্গেটটাইপ একটি রেফারেন্স টাইপ বা মান ধরণের কিনা তা বিবেচনা করে না।

  • জেনেরিকগুলির সাথে জড়িত অন্যান্য ক্ষেত্রেও isদরকারী যেখানে কার্যকর (কারণ আপনি টি জানেন না যে টি একটি রেফারেন্স টাইপ কিনা তাই আপনি এটি হিসাবে ব্যবহার করতে পারবেন না) তবে তারা তুলনামূলকভাবে অস্পষ্ট।

  • আমি প্রায় অবশ্যই isআগে মান টাইপ মামলার জন্য ব্যবহার করেছি, একটি ছোট ছোট টাইপ এবং asএকসাথে ব্যবহার করার কথা চিন্তা করে না :)


সম্পাদনা: নোট করুন যে উপরোক্ত কোনওটিই পারফরম্যান্স সম্পর্কে আলোচনা করে না, মান ধরণের ক্ষেত্রে ব্যতীত, যেখানে আমি উল্লেখ করেছি যে একটি অযোগ্য মান ধরণের আনবক্সিং করা আসলে ধীর - তবে সামঞ্জস্যপূর্ণ।

নাসকিংয়ের উত্তর অনুসারে, নীচের কোডটি দেখানো অনুসারে আধুনিক জেআইটি-র সাথে-ও-কাস্ট বা হ'ল উভয়ই তত দ্রুত:

using System;
using System.Diagnostics;
using System.Linq;

class Test
{
    const int Size = 30000000;

    static void Main()
    {
        object[] values = new object[Size];
        for (int i = 0; i < Size - 2; i += 3)
        {
            values[i] = null;
            values[i + 1] = "x";
            values[i + 2] = new object();
        }
        FindLengthWithIsAndCast(values);
        FindLengthWithIsAndAs(values);
        FindLengthWithAsAndNullCheck(values);
    }

    static void FindLengthWithIsAndCast(object[] values)        
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            if (o is string)
            {
                string a = (string) o;
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Is and Cast: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithIsAndAs(object[] values)        
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            if (o is string)
            {
                string a = o as string;
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Is and As: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithAsAndNullCheck(object[] values)        
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            string a = o as string;
            if (a != null)
            {
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("As and null check: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }
}

আমার ল্যাপটপে, এগুলি প্রায় 60 মিমিতে চালিত হয়। দুটি বিষয় লক্ষণীয়:

  • তাদের মধ্যে কোনও উল্লেখযোগ্য পার্থক্য নেই। (প্রকৃতপক্ষে, এমন পরিস্থিতি রয়েছে যেখানে অস-প্লাস-নাল চেক অবশ্যই হয় ধীর উপরের কোড আসলে কারণ এটি একটি সিল বর্গ জন্য তোলে প্রকার চেক সহজ;। যদি আপনি একটি ইন্টারফেসের জন্য করছি পরীক্ষণ ভারসাম্য টিপস সামান্য হিসাবে-প্লাস-নাল-চেকের পক্ষে)
  • তারা সব করছি অন্যন্ত দ্রুত। আপনি কেবলমাত্র মানগুলি পরে কিছু করতে যাচ্ছেন না যদি না এটি কেবল আপনার কোডের ক্ষেত্রে বাধা হয়ে দাঁড়াবে না

সুতরাং আসুন কর্মক্ষমতা সম্পর্কে চিন্তা করা উচিত না। আসুন নির্ভুলতা এবং ধারাবাহিকতা সম্পর্কে চিন্তা করুন।

আমি বজায় রাখছি যে ভেরিয়েবলগুলির সাথে কাজ করার সময় (এবং-হিসাবে) উভয়ই অনিরাপদ, কারণ এটির যে ধরণের মান উল্লেখ করা হয় তা পরীক্ষা এবং castালাইয়ের মধ্যে অন্য থ্রেডের কারণে পরিবর্তিত হতে পারে। এটি একটি খুব বিরল পরিস্থিতি হবে - তবে আমি বরং একটি কনভেনশন করব যা আমি ধারাবাহিকভাবে ব্যবহার করতে পারি।

আমি এও বজায় রেখেছি যে-পরে-নাল চেক উদ্বেগের আরও ভাল বিভাজন দেয়। আমাদের একটি বিবৃতি আছে যা রূপান্তর চেষ্টা করে এবং তারপরে একটি বিবৃতি যা ফলাফল ব্যবহার করে। হয় এবং কাস্ট বা হয় এবং হিসাবে একটি পরীক্ষা সঞ্চালিত হয় এবং তারপরে মান রূপান্তর করার জন্য আরেকটি প্রচেষ্টা attempt

এটিকে অন্য উপায়ে বলতে গেলে যে কেউ কি কখনও লিখবেন:

int value;
if (int.TryParse(text, out value))
{
    value = int.Parse(text);
    // Use value
}

এটি কী-কাস্ট করছে তা সাজানো - যদিও এটি সম্ভবত সস্তা পন্থায়।


7
এখানে খরচ হয় / যেমন / আইএল পরিপ্রেক্ষিতে ভোটদান: atalasoft.com/cs/blogs/stevehawley/archive/2009/01/30/...
থামাল

3
ক্ষেত্রে, যদি টার্গেটওজেক্ট লক্ষ্যবস্তু হতে পারে, তবে কেন "হয়" এবং combination ালাই সংমিশ্রণটি ব্যবহারকে একটি খারাপ অভ্যাস হিসাবে বিবেচনা করা হবে? মানে, এটি একটি ধীর কোড জেনারেট করে, তবে এই ক্ষেত্রে এএস কাস্টের চেয়ে অভিপ্রায়গুলি আরও স্পষ্ট, যেমন "টার্গেটওজেক্ট যদি টার্গেটটাইপ হয় তবে কিছু করুন" এর পরিবর্তে "টার্গেটওজেক্ট যদি নাল থাকে তবে কিছু করুন" এর পরিবর্তে এএস ক্লজটি একটি অপ্রয়োজনীয় পরিবর্তনশীল তৈরি করবে যদি সুযোগের বাইরে থাকে।
ভ্যালেরা কলুপাইভ

2
@ ভ্যালেরা: ভাল পয়েন্ট, যদিও আমি প্রস্তাব দিচ্ছি যে / নাল পরীক্ষাটি যথেষ্ট পরিমাণে মূর্খতাযুক্ত যে উদ্দেশ্যটি সমস্ত সি # বিকাশকারীদের কাছে পরিষ্কার হওয়া উচিত। আমি ব্যক্তিগতভাবে ব্যক্তিগতভাবে + কাস্টের সাথে জড়িত নকলটি পছন্দ করি না। আমি আসলে একটি ধরণের "as-if" কনস্ট্রাক্ট চাই যা একটিতে উভয় ক্রিয়া করে। তারা প্রায়শই একসাথে চলে যায় ...
জন স্কিটি

2
@ জোন স্কিটি: আমার দেরির জন্য দুঃখিত And 128,000,000 আইটেমের।
বেহরোজ

2
সি # 7 এর সাহায্যে আপনি এটি করতে পারেন: if (randomObject is TargetType convertedRandomObject){ // Do stuff with convertedRandomObject.Value}বা ডক্স ব্যবহার করতে switch/ case দেখতে
WerWet

71

"হিসাবে" কাস্ট করা সম্ভব না হলে NULL ফিরিয়ে দেবে।

আগে কাস্টিং একটি ব্যতিক্রম উত্থাপন করবে।

পারফরম্যান্সের জন্য, ব্যতিক্রম উত্থাপন সাধারণত সময়ে বেশি ব্যয় হয়।


3
ব্যতিক্রম উত্থাপনটি আরও ব্যয়বহুল, তবে আপনি যদি জানেন যে সুরক্ষা চেকের কারণে আরও বেশি সময় প্রয়োজন হিসাবে বস্তুটি সঠিকভাবে কাস্ট করা যেতে পারে (অ্যান্টনের প্রতিক্রিয়া দেখুন)। তবে, সুরক্ষা চেকের ব্যয়টি আমার বিশ্বাস, খুব কম।

17
সম্ভাব্য ব্যতিক্রম উত্থাপণের ব্যয় বিবেচনা করার একটি বিষয়, তবে এটি প্রায়শই সঠিক নকশা হয়।
জেফ্রি এল হুইটলেজ

@ পেণোসফ্লগ্লাস - রেফারেন্সের ধরণের জন্য, রূপান্তর সামঞ্জস্যতা সর্বদা রান এবং সময় উভয়র জন্য রান-টাইমে চেক করা হবে, যাতে ফ্যাক্টর দুটি বিকল্পের মধ্যে পার্থক্য না করে। (যদি এটি না হয়, তবে an
ালাই

4
@ ফ্র্যাঙ্ক - যদি আপনাকে প্রাক-জেনেরিক সংগ্রহের প্রয়োজন হয়, উদাহরণস্বরূপ, এবং আপনার এপিআইতে কোনও পদ্ধতির জন্য কর্মচারীদের একটি তালিকা প্রয়োজন, এবং কিছু জোকার পরিবর্তে পণ্যগুলির একটি তালিকা পাস করে, তবে একটি অবৈধ castালাই ব্যতিক্রম সংকেত দেওয়ার উপযুক্ত হতে পারে ইন্টারফেস প্রয়োজনীয়তা লঙ্ঘন।
জেফরি এল হুইলেটজ

27

কিছু আইএল তুলনা সহ এখানে আরও একটি উত্তর দেওয়া আছে। ক্লাসটি বিবেচনা করুন:

public class MyClass
{
    public static void Main()
    {
        // Call the 2 methods
    }

    public void DirectCast(Object obj)
    {
        if ( obj is MyClass)
        { 
            MyClass myclass = (MyClass) obj; 
            Console.WriteLine(obj);
        } 
    } 


    public void UsesAs(object obj) 
    { 
        MyClass myclass = obj as MyClass; 
        if (myclass != null) 
        { 
            Console.WriteLine(obj);
        } 
    }
}

এখন প্রতিটি পদ্ধতি উত্পন্ন আইএল দেখুন। এমনকি যদি ওপ কোডগুলি আপনার কাছে কিছুই বোঝায় না, আপনি একটি প্রধান পার্থক্য দেখতে পাবেন - আইসাইনস্টকে ডাইরেক্টকাস্ট পদ্ধতিতে কাস্টক্লাস দ্বারা অনুসরণ করা হচ্ছে। মূলত একটির পরিবর্তে দুটি কল।

.method public hidebysig instance void  DirectCast(object obj) cil managed
{
  // Code size       22 (0x16)
  .maxstack  8
  IL_0000:  ldarg.1
  IL_0001:  isinst     MyClass
  IL_0006:  brfalse.s  IL_0015
  IL_0008:  ldarg.1
  IL_0009:  castclass  MyClass
  IL_000e:  pop
  IL_000f:  ldarg.1
  IL_0010:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0015:  ret
} // end of method MyClass::DirectCast

.method public hidebysig instance void  UsesAs(object obj) cil managed
{
  // Code size       17 (0x11)
  .maxstack  1
  .locals init (class MyClass V_0)
  IL_0000:  ldarg.1
  IL_0001:  isinst     MyClass
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  brfalse.s  IL_0010
  IL_000a:  ldarg.1
  IL_000b:  call       void [mscorlib]System.Console::WriteLine(object)
  IL_0010:  ret
} // end of method MyClass::UsesAs

কাস্টক্লাস বনাম আইনিস্ট কীওয়ার্ড

এই ব্লগ পোস্টটি করার দুটি পদ্ধতির মধ্যে শালীন তুলনা রয়েছে। তার সংক্ষিপ্তসারটি হ'ল:

  • প্রত্যক্ষ তুলনায়, আইসনস্ট কাস্টক্লাসের চেয়ে দ্রুত (যদিও কেবল সামান্য)
  • রূপান্তরটি সফল হয়েছে তা নিশ্চিত করার জন্য যখন চেকগুলি সম্পাদন করানো হয়েছিল তখন কাস্টক্লাসের চেয়ে যথেষ্ট দ্রুত ছিল
  • ইসিনস্ট এবং কাস্টক্লাসের সংমিশ্রণটি ব্যবহার করা উচিত নয় কারণ এটি দ্রুততম "নিরাপদ" রূপান্তর (12% এরও বেশি ধীর) চেয়ে ধীর ছিল

আমি ব্যক্তিগতভাবে সর্বদা হিসাবে হিসাবে ব্যবহার করি, কারণ এটি পড়তে সহজ এবং .NET বিকাশ দল (বা যাইহোক জেফ্রি রিখটার) দ্বারা প্রস্তাবিত


আমি বনাম যেমন ingালাইয়ের জন্য স্পষ্ট ব্যাখ্যা খুঁজছিলাম, এই উত্তরটি এটি আরও পরিষ্কার করে তোলে কারণ এটি সাধারণ মধ্যবর্তী ভাষার ধাপে ধাপে ব্যাখ্যা দ্বারা জড়িত। ধন্যবাদ!
মোর্স

18

উভয়ের মধ্যে আরও সূক্ষ্ম পার্থক্যগুলির একটি হ'ল কাস্ট অপারেটর জড়িত থাকার সময় "হিসাবে" কীওয়ার্ডটি কাস্টিংয়ের জন্য ব্যবহার করা যায় না:

public class Foo
{
    public string Value;

    public static explicit operator string(Foo f)
    {
        return f.Value;
    }

}

public class Example
{
    public void Convert()
    {
        var f = new Foo();
        f.Value = "abc";

        string cast = (string)f;
        string tryCast = f as string;
    }
}

"হিসাবে" কীওয়ার্ডগুলি কাস্ট অপারেটরদের অ্যাকাউন্টে নেয় না বলে এটি সর্বশেষ লাইনে সংকলন করবে না (যদিও আমি এটি পূর্ববর্তী সংস্করণে করেছি বলে মনে করি) will লাইন string cast = (string)f;যদিও ঠিক কাজ করে।


12

যেমন কখনো ব্যতিক্রম ছোঁড়ার যদি এটা রূপান্তর ফিরে সঞ্চালন করা সম্ভব নয় নাল পরিবর্তে ( যেমন শুধুমাত্র রেফারেন্সের ধরনের পরিচালনা)। সুতরাং হিসাবে হিসাবে ব্যবহার মূলত সমতুল্য

_myCls2 = _myObj is MyClass ? (MyClass)_myObj : null;

অন্যদিকে সি-স্টাইলের কাস্টগুলি যখন কোনও রূপান্তর সম্ভব না হয় তখন একটি ব্যতিক্রম ছুঁড়ে দেয়।


4
সমান, হ্যাঁ, তবে একই নয়। এটি এরপরে আরও কোড উত্পন্ন করে।
প্লিন্থ

10

আপনার প্রশ্নের উত্তর আসলেই নয়, তবে আমার মনে হয় এটি একটি গুরুত্বপূর্ণ সম্পর্কিত পয়েন্ট।

আপনি যদি কোনও ইন্টারফেসে প্রোগ্রামিং করে থাকেন তবে আপনাকে কাস্ট করার দরকার হবে না। আশা করি এই জাতগুলি খুব বিরল। যদি না হয় তবে আপনার সম্ভবত কিছু ইন্টারফেসের নতুন করে চিন্তা করা দরকার।


Farালাই, এখনও অবধি আমার ইউনিট পরীক্ষার জন্য বেশিরভাগ প্রয়োজন ছিল তবে এটি আনার জন্য আপনাকে ধন্যবাদ। আমি এটি কাজ করার সময় এটি আমার মনে রাখব।
ফ্র্যাঙ্ক ভি

টোডের সাথে একমত, আমি জানতে আগ্রহী কেন ইউনিট পরীক্ষার দিকটি আপনার জন্য ক্রেস্টিং সম্পর্কিত relevant ফ্র্যাঙ্ক ভি। বিভিন্ন সমস্যা জুড়ে রাখতে যেখানে তাদের আলাদাভাবে পরিচালনা করা উচিত।
সিনেটর

@ দ্য সেনেটর এই প্রশ্নটি 3 বছরেরও বেশি পুরনো তাই আমি সত্যিই মনে করি না। ইউনিট টেস্টিংয়ের পরেও আমি সম্ভবত আক্রমণাত্মকভাবে ইন্টারফেসগুলি ব্যবহার করছিলাম। সম্ভবত কারণ আমি ফ্যাক্টরি প্যাটার্নটি ব্যবহার করছিলাম এবং পরীক্ষার লক্ষ্যবস্তুগুলিতে কোনও পাবলিক কনস্ট্রাক্টরের অ্যাক্সেস নেই।
ফ্র্যাঙ্ক ভি

9

অনুগ্রহ করে জন স্কিটির পরামর্শ উপেক্ষা করুন, পুনরায়: পরীক্ষা-ও-কাস্ট প্যাটার্নটি এড়িয়ে চলুন, যেমন:

if (randomObject is TargetType)
{
    TargetType foo = randomObject as TargetType;
    // Do something with foo
}

এই ধারণাটি কাস্টের চেয়ে বেশি এবং নাল পরীক্ষার চেয়ে বেশি হয় এমন একটি মিথ্যুক :

TargetType convertedRandomObject = randomObject as TargetType;
if (convertedRandomObject != null)
{
    // Do stuff with convertedRandomObject
}

এটি একটি মাইক্রো-অপ্টিমাইজেশন যা কাজ করে না। আমি কিছু বাস্তব পরীক্ষা দৌড়েছি , এবং পরীক্ষা-ও-কাস্ট আসলে castালাই-ও-নাল তুলনা তুলনায় দ্রুত এবং এটি আরও নিরাপদ কারণ আপনার যদি কাস্ট করা উচিত তবে বাইরের সুযোগে নাল রেফারেন্স থাকার সম্ভাবনা নেই ব্যর্থ হয়।

আপনি যদি টেস্ট-কাস্ট দ্রুততর বা কমপক্ষে ধীর না হওয়ার কারণ চান তবে একটি সহজ এবং জটিল কারণ রয়েছে।

সরল: এমনকি নিষ্পাপ সংকলকগণ একই পরীক্ষা এবং শাখার মতো দুটি একই ধরণের ক্রিয়াকলাপকে একত্রিত করবেন। castালাই-ও-নাল-পরীক্ষা দুটি পরীক্ষা এবং একটি শাখা জোর করতে পারে, একটি টাইপ টেস্টের জন্য এবং রূপান্তরটি ব্যর্থতার পরে বাতিল করতে পারে, একটি নাল পরীক্ষা করার জন্য। খুব কমপক্ষে, তারা উভয়ই একটি একক পরীক্ষা এবং শাখায় অনুকূলিত হবে, সুতরাং পরীক্ষা-নিরীক্ষা কাস্ট-ও-নাল-পরীক্ষার চেয়ে ধীর বা ত্বরান্বিত হবে না।

জটিল: কেন পরীক্ষা-নিরীক্ষা দ্রুত হয়: কাস্ট-অ্যান্ড নাল-টেস্ট বাইরের স্কোপটিতে আরও একটি পরিবর্তনশীল প্রবর্তন করে যা সংকলককে প্রাণবন্তের জন্য ট্র্যাক করতে হবে এবং এটি আপনার নিয়ন্ত্রণ- কতটা জটিল তার উপর নির্ভর করে সেই পরিবর্তনশীলটিকে অপ্টিমাইজ করতে সক্ষম হতে পারে না- প্রবাহ হয়। বিপরীতভাবে, পরীক্ষা এবং কাস্ট কেবলমাত্র একটি সীমিত স্কোপে নতুন পরিবর্তনশীল প্রবর্তন করে তাই সংকলক জানে যে সুযোগটি প্রস্থান করার পরে ভেরিয়েবলটি মারা গেছে এবং তাই নিবন্ধের বরাদ্দকে আরও ভাল করতে পারেন optim

সুতরাং দয়া করে, দয়া করে এই "কাস্ট-অ্যান্ড নাল-টেস্ট-টেস্ট-কাস্টের চেয়ে ভাল" পরামর্শ ডিআইইকে দিন। অনুগ্রহ. পরীক্ষা এবং কাস্ট উভয়ই নিরাপদ এবং দ্রুত।


7
@ নাস্কিং: আপনি যদি দুবার পরীক্ষা করেন (আপনার প্রথম স্নিপেট অনুসারে), ক্ষেত্র বা refপরামিতি হলে দুটি পরীক্ষার মধ্যে ধরণের পরিবর্তন হওয়ার সম্ভাবনা রয়েছে । এটি স্থানীয় ভেরিয়েবলের জন্য নিরাপদ তবে ক্ষেত্রের জন্য নয়। আমি আপনার মানদণ্ডগুলি চালাতে আগ্রহী, তবে আপনি আপনার ব্লগ পোস্টে যে কোডটি দিয়েছেন তা সম্পূর্ণ নয়। আমি মাইক্রো-অপ্টিমাইজ না করার সাথে একমত, তবে আমি মনে করি না যে "হিসাবে" এবং একটি নালিকা পরীক্ষা ব্যবহারের চেয়ে দুবারের মানটি আরও বেশি পঠনযোগ্য বা মার্জিত। (আমি অবশ্যই বিটিডব্লিউ এর পরে "হিসাবে" না বলে একটি সরাসরি কাস্ট ব্যবহার করব)
জন স্কিটি

5
এটি আরও নিরাপদ কেন আমি তাও দেখছি না। আমি কেন এটি কম নিরাপদ, তা দেখিয়েছি । অবশ্যই, আপনি স্কোপটিতে একটি পরিবর্তনশীল দিয়ে শেষ করেছেন যা শূন্য হতে পারে, তবে আপনি যদি পরবর্তী "যদি" ব্লকের আওতার বাইরে এটি ব্যবহার শুরু না করেন তবে আপনি ভাল আছেন। সুরক্ষা উদ্বেগ যেটি আমি উত্থাপন করেছি (ক্ষেত্রগুলির চারপাশে তাদের মান পরিবর্তন করা) দেখানো কোডটি সহ একটি আসল উদ্বেগ - আপনার সুরক্ষা উদ্বেগ বিকাশকারীদের অন্যান্য কোডে শিথিল হওয়া প্রয়োজন।
জন স্কিটি

1
+1 / castালাই বা castালাই হিসাবে চিহ্নিত করার জন্য বাস্তবে কোনও ধীর গতি নয়, মনে রাখবেন। আমি একটি সম্পূর্ণ পরীক্ষা চালিয়ে যাচ্ছি, আমি নিশ্চিত করতে পারি যতদূর আমি দেখতে পাচ্ছি তাতে কোনও পার্থক্য নেই - এবং সত্যি বলতে আপনি খুব অল্প সময়ে একটি বোগলিং সংখ্যা চালাতে পারেন । আমার কোডটি পুরো কোড দিয়ে আপডেট করবে।
জন স্কিটি

1
প্রকৃতপক্ষে, যদি বাইন্ডিংটি স্থানীয় না হয় তবে সেখানে ট্যাকটিউ বাগের সুযোগ রয়েছে (ব্যবহারের সময় যাচাই-বাছাই করা), তাই ভাল পয়েন্ট। কেন এটি নিরাপদ, আমি অনেক জুনিয়র বিকাশকারীদের সাথে কাজ করি যা কোনও কারণে স্থানীয়দের পুনরায় ব্যবহার করতে পছন্দ করে। কাস্ট-অ্যান্ড-নল আমার অভিজ্ঞতার পক্ষে এইভাবে বিপদজনক এবং আমি আমার কোডটি সেভাবে ডিজাইন করি না বলে আমি কখনও টেকটিউ পরিস্থিতি তৈরি করতে পারি না। রানটাইম পরীক্ষার গতি হিসাবে, এটি ভার্চুয়াল প্রেরণের চেয়েও দ্রুত [1]! পুনঃ কোড, আমি দেখতে পাচ্ছি কিনা আমি কাস্ট পরীক্ষার উত্স খুঁজে পেতে পারি কিনা। [1] Higherlogics.blogspot.com/2008/10/…
নাসকিং

1
@ নাস্কিং: আমি স্থানীয় পুনঃব্যবহারের সমস্যাটিতে কখনই প্রবেশ করিনি - তবে আমি বলব যে কোডটি পর্যালোচনাতে আরও সূক্ষ্ম টেকটিও বাগের চেয়ে স্পট করা আরও সহজ। এটাও উল্লেখ করার মতো যে আমি সিল করা ক্লাসের পরিবর্তে ইন্টারফেসের জন্য আমার নিজের বেঞ্চমার্ক চেকিংটি পুনরায় চালু করেছি এবং সেই-পরে-নাল-চেকের পক্ষে পারফরম্যান্সটির টিপস ... তবে আমি যেমন বলেছি, পারফরম্যান্স আইএনএস আমি এখানে কোনও বিশেষ পদ্ধতি বেছে নেব কেন।
জন স্কিটি

4

কাস্ট ব্যর্থ হলে, 'হিসাবে' কীওয়ার্ডটি ব্যতিক্রম ছুঁড়ে না ফেলে; পরিবর্তে নূন্য (বা মান ধরণের জন্য এটির ডিফল্ট মান) এ পরিবর্তনশীল সেট করে।


3
মান ধরণের জন্য কোনও ডিফল্ট মান নেই। যেমন মূল্য প্রকারের ingালাইয়ের জন্য ব্যবহার করা যায় না।
প্যাট্রিক হাগনে

2
'হিসাবে' কীওয়ার্ডটি আসলে মান ধরণের ক্ষেত্রে কাজ করে না, তাই এটি সর্বদা বাতিল হয়ে যায়।
এরিক ভ্যান ব্র্যাকেল

4

এটি প্রশ্নের উত্তর নয়, তবে প্রশ্নের কোড উদাহরণটিতে মন্তব্য করুন:

সাধারণত আপনাকে আইএমআইআইন্টারফেস থেকে মাই ক্লাসে কোনও অবজেক্ট কাস্ট করতে হবে না। ইন্টারফেসগুলি সম্পর্কে দুর্দান্ত জিনিসটি হ'ল আপনি যদি কোনও বিষয়টিকে ইনপুট হিসাবে গ্রহণ করেন যা কোনও ইন্টারফেস প্রয়োগ করে, আপনি কী ধরণের অবজেক্ট পাচ্ছেন তার যত্ন নেওয়ার দরকার নেই।

আপনি যদি মাইক্লাসে আইএমআইআইন্টারফেসটি castালেন, আপনি ইতিমধ্যে ধরে নিয়েছেন যে আপনি মাইক্লাস টাইপ করেছেন এবং এটি আইএমআইইন্টারফেস ব্যবহার করার কোনও অর্থ রাখে না, কারণ আপনি যদি আইএমইইন্টারফেস প্রয়োগ করে এমন অন্যান্য ক্লাসের সাথে আপনার কোডটি ফিড করেন তবে এটি আপনার কোডটি ভেঙে দেবে ...

এখন, আমার পরামর্শ: আপনার ইন্টারফেসগুলি যদি ভালভাবে ডিজাইন করা হয় তবে আপনি প্রচুর টাইপকাস্টিং এড়াতে পারবেন।


3

asঅপারেটর শুধুমাত্র, রেফারেন্স ধরনের ব্যবহার করা যাবে এটা ওভারলোড করা যাবে না, এবং এটি ফিরে আসবে nullযদি অপারেশন ব্যর্থ। এটি কখনও ব্যতিক্রম ছুঁড়ে ফেলবে না।

Anyালাই কোনও সামঞ্জস্যপূর্ণ ধরণের ক্ষেত্রে ব্যবহার করা যেতে পারে, এটি ওভারলোড করা যায় এবং অপারেশন ব্যর্থ হলে এটি একটি ব্যতিক্রম ছুঁড়ে ফেলবে।

কোনটি ব্যবহার করবেন তা নির্বাচনের উপর নির্ভর করে। প্রাথমিকভাবে, আপনি ব্যর্থ রূপান্তরটিতে কোনও ব্যতিক্রম ছুঁড়তে চান কিনা এটি বিষয় matter


1
'হিসাবে' হ্রাসযোগ্য মান ধরণের ক্ষেত্রেও ব্যবহার করা যেতে পারে, যা একটি আকর্ষণীয় নিদর্শন সরবরাহ করে। কোডের জন্য আমার উত্তর দেখুন।
জন স্কিটি

1

আমার উত্তরটি কেবল তখন গতি সম্পর্কে হয় যখন আমরা প্রকারটি পরীক্ষা করি না এবং ingালাইয়ের পরে নালগুলি পরীক্ষা করি না। আমি জোন স্কিটের কোডে দুটি অতিরিক্ত পরীক্ষা যুক্ত করেছি:

using System;
using System.Diagnostics;

class Test
{
    const int Size = 30000000;

    static void Main()
    {
        object[] values = new object[Size];

        for (int i = 0; i < Size; i++)
        {
            values[i] = "x";
        }
        FindLengthWithIsAndCast(values);
        FindLengthWithIsAndAs(values);
        FindLengthWithAsAndNullCheck(values);

        FindLengthWithCast(values);
        FindLengthWithAs(values);

        Console.ReadLine();
    }

    static void FindLengthWithIsAndCast(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            if (o is string)
            {
                string a = (string)o;
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Is and Cast: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithIsAndAs(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            if (o is string)
            {
                string a = o as string;
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("Is and As: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithAsAndNullCheck(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            string a = o as string;
            if (a != null)
            {
                len += a.Length;
            }
        }
        sw.Stop();
        Console.WriteLine("As and null check: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }
    static void FindLengthWithCast(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            string a = (string)o;
            len += a.Length;
        }
        sw.Stop();
        Console.WriteLine("Cast: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }

    static void FindLengthWithAs(object[] values)
    {
        Stopwatch sw = Stopwatch.StartNew();
        int len = 0;
        foreach (object o in values)
        {
            string a = o as string;
            len += a.Length;
        }
        sw.Stop();
        Console.WriteLine("As: {0} : {1}", len,
                          (long)sw.ElapsedMilliseconds);
    }
}

ফলাফল:

Is and Cast: 30000000 : 88
Is and As: 30000000 : 93
As and null check: 30000000 : 56
Cast: 30000000 : 66
As: 30000000 : 46

গতিতে মনোযোগ দেওয়ার চেষ্টা করবেন না (যেমনটি আমি করেছি) কারণ এগুলি খুব দ্রুত is


একইভাবে, আমার পরীক্ষায়, আমি দেখতে পেয়েছি যে asরূপান্তর (ত্রুটি যাচাই না করে) castালাইয়ের চেয়ে প্রায় 1-3% দ্রুত (প্রায় 540ms বনাম 550ms প্রায় 100 মিলিয়ন পুনরাবৃত্তিতে) দৌড়েছে। আপনার অ্যাপ্লিকেশন তৈরি বা ভঙ্গ করবে না।
পালসুইম

1

এখানে ইতিমধ্যে যা প্রকাশিত হয়েছিল সেগুলি ছাড়াও, আমি কেবল একটি বাস্তব পার্থক্য পেয়েছি যা আমি মনে করি যে উল্লেখযোগ্য,

var x = (T) ...

asঅপারেটর ব্যবহার বনাম ।

এখানে উদাহরণ:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(GenericCaster<string>(12345));
        Console.WriteLine(GenericCaster<object>(new { a = 100, b = "string" }) ?? "null");
        Console.WriteLine(GenericCaster<double>(20.4));

        //prints:
        //12345
        //null
        //20.4

        Console.WriteLine(GenericCaster2<string>(12345));
        Console.WriteLine(GenericCaster2<object>(new { a = 100, b = "string" }) ?? "null");

        //will not compile -> 20.4 does not comply due to the type constraint "T : class"
        //Console.WriteLine(GenericCaster2<double>(20.4));
    }

    static T GenericCaster<T>(object value, T defaultValue = default(T))
    {
        T castedValue;
        try
        {
            castedValue = (T) Convert.ChangeType(value, typeof(T));
        }
        catch (Exception)
        {
            castedValue = defaultValue;
        }

        return castedValue;
    }

    static T GenericCaster2<T>(object value, T defaultValue = default(T)) where T : class
    {
        T castedValue;
        try
        {
            castedValue = Convert.ChangeType(value, typeof(T)) as T;
        }
        catch (Exception)
        {
            castedValue = defaultValue;
        }

        return castedValue;
    }
}

নীচের লাইন: জেনেরিকাস্টার 2 স্ট্রাক্ট ধরণের সাথে কাজ করবে না। জেনেরিকাস্টার করবে।


1

আপনি যদি নেট নেট ফ্রেমওয়ার্ক ৪ এক্স এক্সকে লক্ষ্য করে অফিস পিআইএগুলি ব্যবহার করেন তবে আপনার কীওয়ার্ড হিসাবে ব্যবহার করা উচিত , অন্যথায় এটি সংকলন করবে না।

Microsoft.Office.Interop.Outlook.Application o = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.MailItem m = o.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem) as Microsoft.Office.Interop.Outlook.MailItem;

.NET 2.0 টার্গেট করার সময় কাস্টিং ঠিক আছে:

Microsoft.Office.Interop.Outlook.MailItem m = (Microsoft.Office.Interop.Outlook.MailItem)o.CreateItem(Microsoft.Office.Interop.Outlook.OlItemType.olMailItem);

.NET 4.X টার্গেট করার সময় ত্রুটিগুলি হ'ল:

ত্রুটি CS0656: অনুপস্থিত সংকলকটির প্রয়োজনীয় সদস্য 'মাইক্রোসফ্ট.সিএসআরপি.রুনটাইমবাইন্ডার.বাইন্ডার.কনভার্ট'

ত্রুটি CS0656: অনুপস্থিত সংকলকটির প্রয়োজনীয় সদস্য 'মাইক্রোসফ্ট.সিএসআরপি.রুনটাইমবাইন্ডার.সিএসআরপিআরগমেন্ট ইনফো.ক্রেট'


0

asশব্দ প্রধান পার্থক্য যদি রূপান্তর ব্যর্থ এটি একটি ব্যতিক্রম বাড়াতে না সঙ্গে সামঞ্জস্যপূর্ণ রেফারেন্স ধরনের মধ্যে একটি সুনির্দিষ্ট ঢালাই হিসাবে একই কাজ করে। বরং এটি লক্ষ্য ভেরিয়েবলের একটি নাল মান দেয় yield যেহেতু ব্যতিক্রমগুলি পারফরম্যান্সের ক্ষেত্রে অত্যন্ত ব্যয়বহুল, তাই এটি ingালাইয়ের একটি আরও ভাল পদ্ধতি হিসাবে বিবেচিত হয়।


একজন যেমন কাস্টক্লাসকে কল করে এবং অন্যটি আইএল কোডে ইসিনস্টকে কল করে।
জেনিক্স

0

আপনি যা জোরালোভাবে চয়ন করেন তা নির্ভর করে যা নির্ভর করে। আমি সুস্পষ্ট কাস্টিং পছন্দ করি

IMyInterface = (IMyInterface)someobj;

কারণ যদি আইএমআইআইন্টারফেসের ধরণের মাধ্যমে অবজেক্টটি করা উচিত এবং এটি না হয় - এটি অবশ্যই সমস্যা। যত তাড়াতাড়ি সম্ভব ত্রুটি পাওয়া আরও ভাল কারণ এর পার্শ্ব প্রতিক্রিয়া স্থির করার পরিবর্তে সঠিক ত্রুটি ঠিক করা হবে।

তবে আপনি যদি এমন পদ্ধতিগুলি ব্যবহার করেন objectযা পরামিতি হিসাবে গ্রহণ করে তবে কোনও কোড কার্যকর করার আগে আপনাকে তার সঠিক ধরণের পরীক্ষা করতে হবে। এই জাতীয় ক্ষেত্রে asদরকারী হবে যাতে আপনি এড়াতে পারেন InvalidCastException


0

এটি নির্ভর করে, আপনি কি "হিসাবে" ব্যবহারের পরে নাল পরীক্ষা করতে চান বা আপনি নিজের অ্যাপ্লিকেশনটিকে কোনও ব্যতিক্রম ছুঁড়তে পছন্দ করেন?

আমার থাম্বের নিয়মটি হ'ল যদি আমি সবসময় পরিবর্তনশীল যে ধরণের প্রত্যাশা করি তার সময়টি আমি প্রত্যাশা করি যে সময় আমি কাস্ট ব্যবহার করতে চাই use যদি এটি সম্ভব হয় যে ভেরিয়েবলটি আমার যা চান তা নিক্ষেপ করবে না এবং আমি ব্যবহার হিসাবে নলগুলি হ্যান্ডেল করার জন্য প্রস্তুত, আমি হিসাবে ব্যবহার করব।



0

ওপির সমস্যাটি নির্দিষ্ট কাস্টিং পরিস্থিতিতে সীমাবদ্ধ। শিরোনামে আরও অনেক পরিস্থিতিতে রয়েছে।
এখানে প্রাসঙ্গিক কাস্টিং পরিস্থিতিগুলির একটি সংক্ষিপ্তসার যা আমি বর্তমানে ভাবতে পারি:

private class CBase
{
}

private class CInherited : CBase
{
}

private enum EnumTest
{
  zero,
  one,
  two
}

private static void Main (string[] args)
{
  //########## classes ##########
  // object creation, implicit cast to object
  object oBase = new CBase ();
  object oInherited = new CInherited ();

  CBase oBase2 = null;
  CInherited oInherited2 = null;
  bool bCanCast = false;

  // explicit cast using "()"
  oBase2 = (CBase)oBase;    // works
  oBase2 = (CBase)oInherited;    // works
  //oInherited2 = (CInherited)oBase;   System.InvalidCastException
  oInherited2 = (CInherited)oInherited;    // works

  // explicit cast using "as"
  oBase2 = oBase as CBase;
  oBase2 = oInherited as CBase;
  oInherited2 = oBase as CInherited;  // returns null, equals C++/CLI "dynamic_cast"
  oInherited2 = oInherited as CInherited;

  // testing with Type.IsAssignableFrom(), results (of course) equal the results of the cast operations
  bCanCast = typeof (CBase).IsAssignableFrom (oBase.GetType ());    // true
  bCanCast = typeof (CBase).IsAssignableFrom (oInherited.GetType ());    // true
  bCanCast = typeof (CInherited).IsAssignableFrom (oBase.GetType ());    // false
  bCanCast = typeof (CInherited).IsAssignableFrom (oInherited.GetType ());    // true

  //########## value types ##########
  int iValue = 2;
  double dValue = 1.1;
  EnumTest enValue = EnumTest.two;

  // implicit cast, explicit cast using "()"
  int iValue2 = iValue;   // no cast
  double dValue2 = iValue;  // implicit conversion
  EnumTest enValue2 = (EnumTest)iValue;  // conversion by explicit cast. underlying type of EnumTest is int, but explicit cast needed (error CS0266: Cannot implicitly convert type 'int' to 'test01.Program.EnumTest')

  iValue2 = (int)dValue;   // conversion by explicit cast. implicit cast not possible (error CS0266: Cannot implicitly convert type 'double' to 'int')
  dValue2 = dValue;
  enValue2 = (EnumTest)dValue;  // underlying type is int, so "1.1" beomces "1" and then "one"

  iValue2 = (int)enValue;
  dValue2 = (double)enValue;
  enValue2 = enValue;   // no cast

  // explicit cast using "as"
  // iValue2 = iValue as int;   error CS0077: The as operator must be used with a reference type or nullable type
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.