নাল চেক দিয়ে 'ইজ' বনাম চেষ্টা কাস্ট করুন


107

আমি লক্ষ্য করেছি যে রিশার্পার পরামর্শ দেয় যে আমি এটি ঘুরিয়েছি:

if (myObj.myProp is MyType)
{
   ...
}

এটিতে:

var myObjRef = myObj.myProp as MyType;
if (myObjRef != null)
{
   ...
}

কেন এটি এই পরিবর্তনের পরামর্শ দিবে? অপ্টিমাইজেশনের পরিবর্তন এবং কোড হ্রাস পরিবর্তনের পরামর্শ দেওয়ার জন্য আমি পুনঃভাগে অভ্যস্ত হয়েছি, তবে এটি অনুভব করে যে এটি আমার একক বিবৃতিটি গ্রহণ করে এটি একটি দ্বি-লাইনারে পরিণত করতে চায়।

এমএসডিএন অনুসারে :

একটি হল অভিব্যক্তি সত্য মূল্যায়ণ যদি নিম্নলিখিত অবস্থার উভয় পূরণ করা হয়:

অভিব্যক্তি নাল নয়। এক্সপ্রেশন টাইপ করা যেতে পারে । অর্থাৎ, ফর্মের একটি কাস্ট এক্সপ্রেশন (type)(expression)ব্যতিক্রম ছাড়াই সম্পূর্ণ হবে।

আমি কি এটি ভুলভাবে লিখছি, বা isনাল চেকের জন্য স্পষ্টভাবে অন্য স্থানীয় ভেরিয়েবলটি তৈরি করার প্রয়োজন ছাড়াই ঠিক একই লাইনে চেকগুলি করব না ?


1
আপনি কি কোডটিতে পরে MyObjRef ব্যবহার করছেন? আপনি যদি হন তবে MyPropএই পরিবর্তনের পরে আপনার দরকার হবে না ।
ডিফল্ট

উত্তর:


146

কারণ এখানে কেবল একটি castালাই আছে। এর সাথে তুলনা করুন:

if (myObj.myProp is MyType) // cast #1
{
    var myObjRef = (MyType)myObj.myProp; // needs to be cast a second time
                                         // before using it as a MyType
    ...
}

এটি:

var myObjRef = myObj.myProp as MyType; // only one cast
if (myObjRef != null)
{
    // myObjRef is already MyType and doesn't need to be cast again
    ...
}

সি # 7.0 প্যাটার্ন ম্যাচিং ব্যবহার করে আরও কমপ্যাক্ট সিনট্যাক্স সমর্থন করে :

if (myObj.myProp is MyType myObjRef)
{
    ...
}

3
ঠিক। 'ইজ' ব্যবহার করা মূলত রিটার্নের মতো কিছু করছে ((মাইপ্রাইপ হিসাবে মাইপ্রাইপ) == নাল)
বাম্বু

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

4
এছাড়াও লক্ষ্য করুন যে আসল সংস্করণটি থ্রেড-নিরাপদ নয়। অনাকাঙ্ক্ষিত আচরণের কারণে এবং কাস্টের মধ্যে (অন্য থ্রেড দ্বারা) এর মান myObjবা myPropপরিবর্তন হতে পারে is
জেফ ই

1
আমি আরও যোগ করতে পারি যে as++ ব্যবহার করে সংজ্ঞায়িত হলে != nullওভাররাইড !=অপারেটরটি কার্যকর করা হবে MyType(এমনকি myObjRefনাল হলেও )। যখন অধিকাংশ ক্ষেত্রেই এই একটি অ সমস্যা (বিশেষ করে আপনি সঠিকভাবে তা বাস্তবায়ন হলে), কিছু চরম ক্ষেত্রে (খারাপ কোড, কর্মক্ষমতা) এটি কাম্য নয় হতে পারে। ( যদিও বেশ চূড়ান্ত হতে হবে )
ক্রিস সিনক্লেয়ার

1
@ ক্রিস: ঠিক আছে, কোডটির সঠিক অনুবাদটি ব্যবহার করবে object.ReferenceEquals(null, myObjRef)
বেন ভয়েগট

10

সর্বোত্তম বিকল্পটি হ'ল প্যাটার্ন মেলানো যেমন:

if (value is MyType casted){
    //Code with casted as MyType
    //value is still the same
}
//Note: casted can be used outside (after) the 'if' scope, too

প্রশ্নটি থেকে দ্বিতীয় খণ্ডটির চেয়ে এটি ঠিক কীভাবে ভাল?
ভিক্টর ইয়ারেমা

প্রশ্নের দ্বিতীয় খণ্ডটি হ'ল (পরিবর্তনশীল ঘোষণা ছাড়াই) এর মৌলিক ব্যবহারের কথা উল্লেখ করছে এবং সেক্ষেত্রে আপনি টাইপটি দুটিবার পরীক্ষা করবেন (একটিতে বিবৃতি দেওয়া হয়েছে এবং অভিনয়ের আগে অন্যটি)
ফ্রেঞ্চেসকো ক্যাটোনি

6

বেল্টের নীচে আসলে কী ঘটে যায় সে সম্পর্কে এখনও কোনও তথ্য নেই। এই উদাহরণটি একবার দেখুন:

object o = "test";
if (o is string)
{
    var x = (string) o;
}

এটি নিম্নলিখিত আইএলে অনুবাদ করে:

IL_0000:  nop         
IL_0001:  ldstr       "test"
IL_0006:  stloc.0     // o
IL_0007:  ldloc.0     // o
IL_0008:  isinst      System.String
IL_000D:  ldnull      
IL_000E:  cgt.un      
IL_0010:  stloc.1     
IL_0011:  ldloc.1     
IL_0012:  brfalse.s   IL_001D
IL_0014:  nop         
IL_0015:  ldloc.0     // o
IL_0016:  castclass   System.String
IL_001B:  stloc.2     // x
IL_001C:  nop         
IL_001D:  ret   

এখানে যা গুরুত্বপূর্ণ তা হ'ল isinstএবং castclassকলগুলি - উভয়ই তুলনামূলকভাবে ব্যয়বহুল। আপনি যদি বিকল্পটির সাথে এটি তুলনা করেন তবে দেখতে পাবেন এটি কেবল একটি isinstচেক করে:

object o = "test";
var oAsString = o as string;
if (oAsString != null)
{

}

IL_0000:  nop         
IL_0001:  ldstr       "test"
IL_0006:  stloc.0     // o
IL_0007:  ldloc.0     // o
IL_0008:  isinst      System.String
IL_000D:  stloc.1     // oAsString
IL_000E:  ldloc.1     // oAsString
IL_000F:  ldnull      
IL_0010:  cgt.un      
IL_0012:  stloc.2     
IL_0013:  ldloc.2     
IL_0014:  brfalse.s   IL_0018
IL_0016:  nop         
IL_0017:  nop         
IL_0018:  ret  

উল্লেখ করার মতো বিষয় হ'ল একটি মান ধরণের unbox.anyপরিবর্তে ব্যবহৃত হবে castclass:

object o = 5;
if (o is int)
{
    var x = (int)o;
}

IL_0000:  nop         
IL_0001:  ldc.i4.5    
IL_0002:  box         System.Int32
IL_0007:  stloc.0     // o
IL_0008:  ldloc.0     // o
IL_0009:  isinst      System.Int32
IL_000E:  ldnull      
IL_000F:  cgt.un      
IL_0011:  stloc.1     
IL_0012:  ldloc.1     
IL_0013:  brfalse.s   IL_001E
IL_0015:  nop         
IL_0016:  ldloc.0     // o
IL_0017:  unbox.any   System.Int32
IL_001C:  stloc.2     // x
IL_001D:  nop         
IL_001E:  ret   

তবে মনে রাখবেন, এই অগত্যা একটি দ্রুত অনুবাদ ফলে আমরা দেখতে পারি এখানে । যদিও এই প্রশ্নটি জিজ্ঞাসা করার পরেও উন্নতি হয়েছে বলে মনে হচ্ছে: বর্ণগুলি আগে যেভাবে করা হত তত দ্রুত সঞ্চালিত হয়েছে বলে মনে হয় asএবং linqএখন প্রায় 3 গুণ দ্রুত।


4

পুনঃভাগ সতর্কতা:

"Type check and direct cast can be replaced with try cast and check for null"

উভয়ই কাজ করবে, এটি নির্ভর করে যে আপনার কোডটি আপনাকে কীভাবে আরও বেশি উপযুক্ত করে। আমার ক্ষেত্রে আমি কেবল সেই সতর্কতাটিকে উপেক্ষা করছি:

//1st way is n+1 times of casting
if (x is A) ((A)x).Run();
else if (x is B) ((B)x).Run();
else if (x is C) ((C)x).Run();
else if (x is D) ((D)x).Run();
//...
else if (x is N) ((N)x).Run();    
//...
else if (x is Z) ((Z)x).Run();

//2nd way is z times of casting
var a = x as Type A;
var b = x as Type B;
var c = x as Type C;
//..
var n = x as Type N;
//..
var z = x as Type Z;
if (a != null) a.Run();
elseif (b != null) b.Run();
elseif (c != null) c.Run();
...
elseif (n != null) n.Run();
...
elseif (x != null) x.Run();

আমার কোড 2 য় উপায় দীর্ঘ এবং খারাপ কর্মক্ষমতা।


1
আপনার বাস্তব-বিশ্বের উদাহরণে কেবল একটি নকশার সমস্যা রয়েছে is আপনি যদি প্রকারগুলি নিয়ন্ত্রণ করেন তবে কেবলমাত্র একটি ইন্টারফেস ব্যবহার করুন IRunable। আপনি যদি নিয়ন্ত্রণ না পেয়ে থাকেন তবে সম্ভবত আপনি ব্যবহার করতে পারেন dynamic?
এম মিম্পেন

3

আমার কাছে এটি নির্ভর করে কি প্রতিকূলতার উপর নির্ভর করে যে এটি সেই ধরণের হতে চলেছে বা না। বস্তুটি বেশিরভাগ সময় যদি সেই ধরণের হয় তবে অবশ্যই অবশ্যই সামনে theালাই করা আরও দক্ষ। যদি এটি কেবলমাত্র কখনও কখনও সেই ধরণের হয় তবে প্রথমে এটি যাচাই করা আরও অনুকূল হতে পারে।

প্রকারের চেকের ব্যয়ের তুলনায় লোকাল ভেরিয়েবল তৈরির ব্যয় খুব নগন্য।

পাঠযোগ্যতা এবং সুযোগ আমার জন্য সাধারণত আরও গুরুত্বপূর্ণ কারণ important আমি রিশার্পারের সাথে একমত নই, এবং একার জন্যই "হ'ল" অপারেটরটি ব্যবহার করব; এটি যদি সত্যিকারের বাধা হয়ে থাকে তবে পরে অনুকূলিত করুন।

(আমি ধরে নিচ্ছি যে আপনি এই ফাংশনটিতে কেবল myObj.myProp is MyTypeএকবার ব্যবহার করছেন )


0

এটি পাশাপাশি দ্বিতীয় পরিবর্তনটির পরামর্শ দেওয়া উচিত:

(MyType)myObj.myProp

মধ্যে

myObjRef

এটি আসল কোডের সাথে তুলনা করে একটি সম্পত্তির অ্যাক্সেস এবং castালাই সংরক্ষণ করে। তবে এটি পরিবর্তন isকরার পরেই সম্ভব as


@ ডিফল্ট: না, তা নয়। এর অর্থ এই নয় যে এটি কোডে নেই।
বেন ভয়েগট

1
দুঃখিত .. ভুল বোঝাবুঝি তবে, (MyType)কাস্ট ব্যর্থ হলে ব্যতিক্রম ছুঁড়ে ফেলবে। asকেবল ফেরত দেয় null
ডিফল্ট

@ ডিফল্ট: কাস্ট ব্যর্থ হবে না, কারণ প্রকারটি ইতিমধ্যে পরীক্ষা করা হয়েছে is(সেই কোডটি প্রশ্নে রয়েছে)।
বেন ভয়েগট

1
তবে, পুনরায় # এই কোডটি প্রতিস্থাপন করতে চায় - এর অর্থ প্রস্তাবিত পরিবর্তনের পরে এটি হবে না।
ডিফল্ট

আমি মনে করি আমি এখানে আপনার চিন্তা অনুসরণ করছি (আমাকে কিছুটা সময় নিয়েছে)। আপনি বলতে চাচ্ছেন যে প্রথম লাইন হয় কোডে কোথাও এবং যে লাইন দ্বিতীয় লাইন পুনঃ # পরামর্শ পর সরলীকৃত করা হবে?
ডিফল্ট

0

আমি এটি বলব এটি মাইওবিজেএমপিপ্রপের একটি দৃ of়-টাইপিত সংস্করণ তৈরি করা, যা আমার ওবিজেআরএফ। এটি তখন ব্যবহার করা উচিত যখন আপনি ব্লকের এই মানটি উল্লেখ করছেন, বনাম একটি কাস্ট করতে হবে।

উদাহরণস্বরূপ, এটি:

myObjRef.SomeProperty

এর থেকে ভাল:

((MyType)myObj.myProp).SomeProperty
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.