रेखा के नीचे उत्तर 2008 में लिखा गया था।
C # 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
, यदि ऐसा नहीं है, तो इसका मतलब है कि बग है, तो कास्टिंग सही समाधान है। यह एक अपवाद को तुरंत फेंक देता है, जिसका अर्थ है कि कोई भी काम गलत धारणाओं के तहत नहीं किया गया है, और अपवाद सही ढंग से बग के प्रकार को दर्शाता है।
// 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
}
(नोट: वर्तमान में यह वास्तव में + कलाकारों की तुलना में धीमा है । मुझे लगता है कि यह अधिक सुरुचिपूर्ण और सुसंगत है, लेकिन वहां हम जाते हैं।)
यदि आपको वास्तव में परिवर्तित मूल्य की आवश्यकता नहीं है, लेकिन आपको यह जानने की जरूरत है कि क्या यह टारगेट का एक उदाहरण है, तो 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);
}
}
मेरे लैपटॉप पर, ये सभी लगभग 60ms में निष्पादित होते हैं। ध्यान देने योग्य दो बातें:
- उनके बीच कोई महत्वपूर्ण अंतर नहीं है। (वास्तव में, ऐसी परिस्थितियां हैं जिनमें एज़-प्लस-नल-चेक निश्चित रूप से धीमा है। उपरोक्त कोड वास्तव में टाइप चेक को आसान बनाता है क्योंकि यह एक सील वर्ग के लिए है; यदि आप एक इंटरफ़ेस के लिए जाँच कर रहे हैं, तो संतुलन थोड़ा सुझाव देता है। as-plus-null-check के पक्ष में।)
- वे सब बहुत तेजी से कर रहे हैं । यह केवल आपके कोड में अड़चन नहीं होगा जब तक आप वास्तव में मूल्यों के साथ कुछ भी नहीं करने जा रहे हैं ।
तो चलो प्रदर्शन के बारे में चिंता मत करो। चलो शुद्धता और स्थिरता के बारे में चिंता करते हैं।
मैं यह सुनिश्चित करता हूं कि चर के साथ काम करते समय और-कास्ट (या-और-के रूप में) दोनों असुरक्षित हैं, क्योंकि परीक्षण और कलाकारों के बीच एक और धागे के कारण इसके प्रकार का मान बदल सकता है। यह एक बहुत ही दुर्लभ स्थिति होगी - लेकिन मेरे पास एक सम्मेलन होगा जो मैं लगातार उपयोग कर सकता हूं।
मैं यह भी बनाए रखता हूं कि जब-तब-शून्य-जांच चिंताओं को बेहतर ढंग से अलग करती है। हमारे पास एक कथन है जो रूपांतरण का प्रयास करता है, और फिर एक कथन जो परिणाम का उपयोग करता है। Is-and-cast या is-and-as एक परीक्षण करता है और फिर मूल्य बदलने के लिए एक और प्रयास।
इसे दूसरे तरीके से रखने के लिए, क्या कोई कभी लिख पाएगा :
int value;
if (int.TryParse(text, out value))
{
value = int.Parse(text);
// Use value
}
यह इस प्रकार है कि क्या-और-कास्ट कर रहा है - हालांकि स्पष्ट रूप से एक सस्ता तरीके से।