C# Language
सी # 6.0 सुविधाएँ
खोज…
परिचय
सी # भाषा का यह छठा पुनरावृत्ति रोसलिन संकलक द्वारा प्रदान किया गया है। यह कंपाइलर .NET फ्रेमवर्क के संस्करण 4.6 के साथ सामने आया है, हालाँकि यह पिछले फ्रेमवर्क संस्करणों को लक्षित करने की अनुमति देने के लिए एक बैकवर्ड संगत तरीके से कोड उत्पन्न कर सकता है। C # संस्करण 6 कोड को पूरी तरह से पीछे संगत तरीके से .NET 4.0 में संकलित किया जा सकता है। इसका उपयोग पहले के ढांचे के लिए भी किया जा सकता है, हालांकि कुछ सुविधाओं के लिए अतिरिक्त ढांचे के समर्थन की आवश्यकता होती है जो सही ढंग से काम नहीं कर सकते हैं।
टिप्पणियों
C # का छठा संस्करण जुलाई 2015 को Visual Studio 2015 और .NET 4.6 के साथ जारी किया गया था।
कुछ नई भाषा सुविधाओं को जोड़ने के साथ-साथ इसमें कंपाइलर का पूरा पुनर्लेखन भी शामिल है। पहले csc.exe
C ++ में लिखा गया एक देशी Win32 अनुप्रयोग था, C # 6 के साथ यह अब C .NET में लिखा गया एक .NET प्रबंधित अनुप्रयोग है। इस पुनर्लेखन को प्रोजेक्ट "रोसलिन" के रूप में जाना जाता था और कोड अब खुला स्रोत है और गिटहब पर उपलब्ध है ।
संचालक का नाम
nameof
ऑपरेटर एक string
रूप में कोड तत्व का नाम देता है। यह विधि के तर्कों से संबंधित अपवादों को फेंकने के दौरान और INotifyPropertyChanged
लागू करते समय भी उपयोगी है।
public string SayHello(string greeted)
{
if (greeted == null)
throw new ArgumentNullException(nameof(greeted));
Console.WriteLine("Hello, " + greeted);
}
nameof
ऑपरेटर का संकलन समय पर किया जाता है और अभिव्यक्ति को एक स्ट्रिंग शाब्दिक में बदल देता है। यह उन स्ट्रिंग्स के लिए भी उपयोगी है जो उनके सदस्य के नाम पर हैं जो उन्हें उजागर करते हैं। निम्नलिखित को धयान मे रखते हुए:
public static class Strings
{
public const string Foo = nameof(Foo); // Rather than Foo = "Foo"
public const string Bar = nameof(Bar); // Rather than Bar = "Bar"
}
चूंकि nameof
अभिव्यक्तियाँ संकलन-समय स्थिरांक हैं, इसलिए उनका उपयोग विशेषताओं, case
लेबल, switch
स्टेटमेंट और इसी तरह किया जा सकता है।
Enum
s के साथ nameof
का उपयोग करना सुविधाजनक है। के बजाय:
Console.WriteLine(Enum.One.ToString());
इसका उपयोग करना संभव है:
Console.WriteLine(nameof(Enum.One))
आउटपुट दोनों मामलों में One
होगा।
nameof
संचालक स्थैतिक-जैसे सिंटैक्स का उपयोग करके गैर-स्थैतिक सदस्यों तक पहुंच सकता है। करने के बजाय:
string foo = "Foo";
string lengthName = nameof(foo.Length);
के साथ प्रतिस्थापित किया जा सकता है:
string lengthName = nameof(string.Length);
आउटपुट दोनों उदाहरणों में Length
होगी। हालांकि, उत्तरार्द्ध अनावश्यक उदाहरणों के निर्माण को रोकता है।
हालांकि nameof
ऑपरेटर अधिकांश भाषा निर्माणों के साथ काम करता है, लेकिन कुछ सीमाएँ हैं। उदाहरण के लिए, आप खुले सामान्य प्रकार या विधि रिटर्न मान पर nameof
ऑपरेटर का उपयोग नहीं कर सकते हैं:
public static int Main()
{
Console.WriteLine(nameof(List<>)); // Compile-time error
Console.WriteLine(nameof(Main())); // Compile-time error
}
इसके अलावा, यदि आप इसे सामान्य प्रकार पर लागू करते हैं, तो सामान्य प्रकार के पैरामीटर को अनदेखा कर दिया जाएगा:
Console.WriteLine(nameof(List<int>)); // "List"
Console.WriteLine(nameof(List<bool>)); // "List"
अधिक उदाहरणों के लिए, इस विषय को nameof
को समर्पित देखें।
पिछले संस्करणों के लिए समाधान ( अधिक विवरण )
हालाँकि, 6.0 से पहले के संस्करणों के लिए nameof
ऑपरेटर C # में मौजूद नहीं है, फिर भी निम्नलिखित के रूप में nameof
कार्यक्षमता का MemberExpression
करके समान कार्यक्षमता हो सकती है:
अभिव्यक्ति:
public static string NameOf<T>(Expression<Func<T>> propExp)
{
var memberExpression = propExp.Body as MemberExpression;
return memberExpression != null ? memberExpression.Member.Name : null;
}
public static string NameOf<TObj, T>(Expression<Func<TObj, T>> propExp)
{
var memberExpression = propExp.Body as MemberExpression;
return memberExpression != null ? memberExpression.Member.Name : null;
}
उपयोग:
string variableName = NameOf(() => variable);
string propertyName = NameOf((Foo o) => o.Bar);
ध्यान दें कि इस दृष्टिकोण के कारण हर कॉल पर एक अभिव्यक्ति ट्री बनाया जाता है, इसलिए nameof
ऑपरेटर की तुलना में प्रदर्शन बहुत खराब होता है जिसका संकलन समय पर मूल्यांकन किया जाता है और रनटाइम पर शून्य ओवरहेड होता है।
अभिव्यक्ति शारीरिक समारोह के सदस्य
अभिव्यक्ति शारीरिक समारोह के सदस्य सदस्यों के रूप में लैम्ब्डा अभिव्यक्ति के उपयोग की अनुमति देते हैं। सरल सदस्यों के लिए, इसका परिणाम क्लीनर और अधिक पठनीय कोड हो सकता है।
एक्सप्रेशन-बॉडीड फ़ंक्शंस का उपयोग गुण, अनुक्रमणिका, विधियों और ऑपरेटरों के लिए किया जा सकता है।
गुण
public decimal TotalPrice => BasePrice + Taxes;
के बराबर है:
public decimal TotalPrice
{
get
{
return BasePrice + Taxes;
}
}
जब एक संपत्ति के साथ एक अभिव्यक्ति-शरीर फ़ंक्शन का उपयोग किया जाता है, तो संपत्ति को गेट-ओनली संपत्ति के रूप में लागू किया जाता है।
indexers
public object this[string key] => dictionary[key];
के बराबर है:
public object this[string key]
{
get
{
return dictionary[key];
}
}
तरीके
static int Multiply(int a, int b) => a * b;
के बराबर है:
static int Multiply(int a, int b)
{
return a * b;
}
जिसका उपयोग void
विधियों के साथ भी किया जा सकता है:
public void Dispose() => resource?.Dispose();
ToString
का एक ओवरराइड Pair<T>
वर्ग में जोड़ा जा सकता है:
public override string ToString() => $"{First}, {Second}";
इसके अतिरिक्त, यह सरलीकृत दृष्टिकोण override
कीवर्ड के साथ काम करता है:
public class Foo
{
public int Bar { get; }
public string override ToString() => $"Bar: {Bar}";
}
ऑपरेटर्स
यह भी ऑपरेटरों द्वारा इस्तेमाल किया जा सकता है:
public class Land
{
public double Area { get; set; }
public static Land operator +(Land first, Land second) =>
new Land { Area = first.Area + second.Area };
}
सीमाएं
अभिव्यक्ति-शारीरिक समारोह के सदस्यों की कुछ सीमाएँ हैं। वे ब्लॉक स्टेटमेंट और किसी भी अन्य स्टेटमेंट को शामिल नहीं कर सकते हैं जिसमें ब्लॉक हैं: if
, switch
, for
, foreach
, while
, do
, try
, आदि।
कुछ if
बयान त्रिगुट ऑपरेटरों के साथ बदला जा सकता है। उदाहरण के for
कुछ और foreach
स्टेटमेंट को LINQ प्रश्नों में बदला जा सकता है:
IEnumerable<string> Digits
{
get
{
for (int i = 0; i < 10; i++)
yield return i.ToString();
}
}
IEnumerable<string> Digits => Enumerable.Range(0, 10).Select(i => i.ToString());
अन्य सभी मामलों में, फ़ंक्शन सदस्यों के लिए पुराने सिंटैक्स का उपयोग किया जा सकता है।
एक्सप्रेशन-बॉडीड फ़ंक्शन के सदस्यों में async
/ await
शामिल हो सकती है, लेकिन यह अक्सर बेमानी है:
async Task<int> Foo() => await Bar();
के साथ प्रतिस्थापित किया जा सकता है:
Task<int> Foo() => Bar();
अपवाद फ़िल्टर
अपवाद फ़िल्टर डेवलपर्स को कैच ब्लॉक में एक शर्त ( boolean
एक्सप्रेशन के रूप में) जोड़ने की सुविधा देते हैं, जिससे catch
को तभी निष्पादित किया जा सकता true
जब स्थिति true
मूल्यांकन करती true
।
अपवाद फ़िल्टर मूल अपवाद में डिबग जानकारी के प्रसार की अनुमति देते हैं, जहां catch
ब्लॉक के अंदर एक if
स्टेटमेंट का उपयोग करने और अपवाद को फिर से फेंकने से डिबग जानकारी का प्रसार मूल अपवाद में बंद हो जाता है। अपवाद फ़िल्टर के साथ, अपवाद तब तक कॉल स्टैक में ऊपर की ओर फैलता रहता है जब तक कि शर्त पूरी नहीं हो जाती। नतीजतन, अपवाद फ़िल्टर डिबगिंग अनुभव को बहुत आसान बनाते हैं। throw
स्टेटमेंट पर रोक के बजाय, डिबगर अपवाद को फेंकने वाले स्टेटमेंट पर रोक देगा, वर्तमान स्थिति और सभी स्थानीय चर के साथ संरक्षित। क्रैश डंप एक समान तरीके से प्रभावित होते हैं।
अपवाद फिल्टर शुरुआत से ही CLR द्वारा समर्थित हैं और वे CLR के अपवाद हैंडलिंग मॉडल के एक भाग को उजागर करके एक दशक से अधिक समय तक VB.NET और F # से सुलभ रहे हैं। C # 6.0 की रिलीज़ के बाद ही C # डेवलपर्स के लिए भी कार्यक्षमता उपलब्ध है।
अपवाद फिल्टर का उपयोग करना
एक्सेप्शन क्लॉज़ का उपयोग when
किया जाता है when
क्लॉज़ को catch
एक्सप्रेशन के लिए जोड़ा जाता है। किसी भी अभिव्यक्ति का उपयोग तब करना संभव है, when
एक क्लॉज ( प्रतीक्षा को छोड़कर) में एक bool
लौट आए। घोषित अपवाद चर ex
when
खंड के भीतर से सुलभ हो:
var SqlErrorToIgnore = 123;
try
{
DoSQLOperations();
}
catch (SqlException ex) when (ex.Number != SqlErrorToIgnore)
{
throw new Exception("An error occurred accessing the database", ex);
}
when
क्लॉज़ को संयोजित किया जा सकता है, when
मल्टीपल catch
ब्लॉक। पहला when
क्लॉज रिटर्निंग true
होगा तो अपवाद को पकड़ा जाएगा। इसके catch
ब्लॉक में प्रवेश किया जाएगा, जबकि अन्य catch
क्लॉज़ को अनदेखा किया जाएगा ( when
क्लॉस का मूल्यांकन नहीं किया जाएगा)। उदाहरण के लिए:
try
{ ... }
catch (Exception ex) when (someCondition) //If someCondition evaluates to true,
//the rest of the catches are ignored.
{ ... }
catch (NotImplementedException ex) when (someMethod()) //someMethod() will only run if
//someCondition evaluates to false
{ ... }
catch(Exception ex) // If both when clauses evaluate to false
{ ... }
क्लॉज होने पर जोखिम भरा
सावधान
यह अपवाद फिल्टर का उपयोग करने के लिए जोखिम भरा हो सकता है: जब एक
Exception
से भीतर फेंक दिया जाता हैwhen
खंड,Exception
सेwhen
खंड पर ध्यान नहीं दिया जाता है और माना जाता हैfalse
। यह दृष्टिकोण डेवलपर्स को लिखने की अनुमति देता हैwhen
अमान्य मामलों की देखभाल के बिना क्लॉज।
निम्न उदाहरण ऐसे परिदृश्य को दर्शाता है:
public static void Main()
{
int a = 7;
int b = 0;
try
{
DoSomethingThatMightFail();
}
catch (Exception ex) when (a / b == 0)
{
// This block is never reached because a / b throws an ignored
// DivideByZeroException which is treated as false.
}
catch (Exception ex)
{
// This block is reached since the DivideByZeroException in the
// previous when clause is ignored.
}
}
public static void DoSomethingThatMightFail()
{
// This will always throw an ArgumentNullException.
Type.GetType(null);
}
ध्यान दें कि जब एक ही फ़ंक्शन के भीतर कोड throw
होता है, तो अपवाद फ़िल्टर नंबर का उपयोग करने से जुड़ी भ्रामक रेखा संख्या समस्याओं से बचते हैं। उदाहरण के लिए इस मामले में लाइन संख्या 3 के बजाय 6 बताई गई है:
1. int a = 0, b = 0;
2. try {
3. int c = a / b;
4. }
5. catch (DivideByZeroException) {
6. throw;
7. }
अपवाद पंक्ति संख्या को 6 के रूप में रिपोर्ट किया जाता है क्योंकि त्रुटि पकड़ी गई थी और पंक्ति 6 पर throw
कथन के साथ फिर से फेंक दी गई थी।
अपवाद फ़िल्टर के साथ भी ऐसा नहीं होता है:
1. int a = 0, b = 0;
2. try {
3. int c = a / b;
4. }
5. catch (DivideByZeroException) when (a != 0) {
6. throw;
7. }
इस उदाहरण में a
0 है तो catch
क्लॉज़ को अनदेखा कर दिया जाता है लेकिन 3 को लाइन नंबर के रूप में सूचित किया जाता है। ऐसा इसलिए है क्योंकि वे स्टैक को खोलना नहीं चाहते हैं । अधिक विशेष रूप से, अपवाद को लाइन 5 पर नहीं पकड़ा गया है क्योंकि वास्तव में a
बराबर 0
करता है और इस प्रकार अपवाद के लिए लाइन 6 पर फिर से फेंकने का कोई अवसर नहीं है क्योंकि लाइन 6 निष्पादित नहीं करता है।
एक साइड इफेक्ट के रूप में लॉगिंग
स्थिति में विधि कॉल साइड इफेक्ट्स का कारण बन सकती है, इसलिए अपवाद फ़िल्टर को बिना पकड़े अपवादों पर कोड चलाने के लिए उपयोग किया जा सकता है। एक सामान्य उदाहरण जो इसका लाभ उठाता है वह एक Log
विधि है जो हमेशा false
तरीके से लौटती false
। यह अपवाद को पुन: फेंकने की आवश्यकता के बिना डीबग करते समय लॉग जानकारी ट्रेस करने की अनुमति देता है।
ध्यान रखें कि जबकि यह लॉगिंग का एक आरामदायक तरीका लगता है, यह जोखिम भरा हो सकता है, खासकर अगर 3 पार्टी लॉगिंग असेंबलियों का उपयोग किया जाता है। ये गैर-स्पष्ट स्थितियों में लॉग इन करते समय अपवादों को फेंक सकते हैं जो आसानी से पता नहीं लगा सकते हैं (ऊपर जोखिम देखें
when(...)
ऊपर क्लॉज ))।
try
{
DoSomethingThatMightFail(s);
}
catch (Exception ex) when (Log(ex, "An error occurred"))
{
// This catch block will never be reached
}
// ...
static bool Log(Exception ex, string message, params object[] args)
{
Debug.Print(message, args);
return false;
}
C # के पिछले संस्करणों में सामान्य दृष्टिकोण अपवाद को लॉग और री-थ्रो करना था।
try
{
DoSomethingThatMightFail(s);
}
catch (Exception ex)
{
Log(ex, "An error occurred");
throw;
}
// ...
static void Log(Exception ex, string message, params object[] args)
{
Debug.Print(message, args);
}
finally
ब्लॉक
finally
ब्लॉक हर बार निष्पादित करता है कि क्या अपवाद फेंक दिया गया है या नहीं। में भाव के साथ एक सूक्ष्मता when
है अपवाद फिल्टर भीतरी प्रवेश करने से पहले ढेर आगे क्रियान्वित कर रहे हैं finally
ब्लॉक। यह अप्रत्याशित परिणाम और व्यवहार का कारण बन सकता है जब कोड वैश्विक स्थिति (वर्तमान थ्रेड उपयोगकर्ता या संस्कृति की तरह) को संशोधित करने का प्रयास करता है और इसे finally
ब्लॉक में वापस सेट करता है।
उदाहरण: finally
ब्लॉक
private static bool Flag = false;
static void Main(string[] args)
{
Console.WriteLine("Start");
try
{
SomeOperation();
}
catch (Exception) when (EvaluatesTo())
{
Console.WriteLine("Catch");
}
finally
{
Console.WriteLine("Outer Finally");
}
}
private static bool EvaluatesTo()
{
Console.WriteLine($"EvaluatesTo: {Flag}");
return true;
}
private static void SomeOperation()
{
try
{
Flag = true;
throw new Exception("Boom");
}
finally
{
Flag = false;
Console.WriteLine("Inner Finally");
}
}
उत्पादित उत्पादन:
शुरू
मूल्यांकन: सच
अंत में
पकड़
अंत में बाहरी
, उपरोक्त विधि अगर उदाहरण में SomeOperation
नहीं करना चाहता है "लीक" फोन करने वाले का करने के लिए वैश्विक स्थिति परिवर्तन when
खंड, यह भी एक को शामिल करना चाहिए catch
स्थिति संशोधित करने के ब्लॉक। उदाहरण के लिए:
private static void SomeOperation()
{
try
{
Flag = true;
throw new Exception("Boom");
}
catch
{
Flag = false;
throw;
}
finally
{
Flag = false;
Console.WriteLine("Inner Finally");
}
}
IDisposable
सहायक वर्गों को एक ही लक्ष्य को प्राप्त करने के लिए ब्लॉकों का उपयोग करने के शब्दार्थ का उपयोग करते हुए देखना भी आम है, क्योंकि IDisposable.Dispose
हमेशा एक अपवाद से पहले बुलाया जाएगा जिसका using
ब्लॉक using
स्टैक को बुदबुदाना शुरू होता है।
ऑटो-प्रॉपर्टी इनिशियलाइज़र
परिचय
गुण के साथ प्रारंभ किया जा सकता है =
समापन के बाद ऑपरेटर }
। नीचे दिया गया Coordinate
वर्ग किसी संपत्ति को आरम्भ करने के लिए उपलब्ध विकल्पों को दर्शाता है:
public class Coordinate
{
public int X { get; set; } = 34; // get or set auto-property with initializer
public int Y { get; } = 89; // read-only auto-property with initializer
}
अलग-अलग दृश्यता वाले एक्सेसर्स
आप ऐसे ऑटो-प्रॉपर्टीज़ को इनिशियलाइज़ कर सकते हैं जिनकी एक्सेसर्स पर अलग-अलग विजिबिलिटी है। यहां एक संरक्षित सेटर के साथ एक उदाहरण दिया गया है:
public string Name { get; protected set; } = "Cheeze";
internal
, internal protected
या private
भी हो सकता है।
पढ़ें- केवल गुण
दृश्यता के साथ लचीलेपन के अलावा, आप केवल पढ़ने योग्य ऑटो-संपत्तियों को भी इनिशियलाइज़ कर सकते हैं। यहाँ एक उदाहरण है:
public List<string> Ingredients { get; } =
new List<string> { "dough", "sauce", "cheese" };
यह उदाहरण यह भी दिखाता है कि किसी संपत्ति को एक जटिल प्रकार से कैसे आरंभ किया जाए। इसके अलावा, ऑटो-प्रॉपर्टीज केवल-राइट नहीं किया जा सकता है, इसलिए यह केवल राइट-इनिशियलाइज़ेशन को भी रोकता है।
पुरानी शैली (पूर्व C # 6.0)
C # 6 से पहले, यह बहुत अधिक क्रिया कोड की आवश्यकता थी। हम संपत्ति के लिए डिफ़ॉल्ट मान देने या नीचे की तरह सार्वजनिक संपत्ति को इनिशियलाइज़ करने के लिए एक अतिरिक्त चर का उपयोग कर रहे थे,
public class Coordinate
{
private int _x = 34;
public int X { get { return _x; } set { _x = value; } }
private readonly int _y = 89;
public int Y { get { return _y; } }
private readonly int _z;
public int Z { get { return _z; } }
public Coordinate()
{
_z = 42;
}
}
नोट: C # 6.0 से पहले, आप अभी भी निर्माण के भीतर से ऑटो कार्यान्वित की गई संपत्तियों (एक गटर और एक सेटर के साथ गुण) को आरंभीकृत कर सकते थे, लेकिन आप इसकी घोषणा के साथ संपत्ति इनलाइन को प्रारंभ नहीं कर सकते थे
प्रयोग
आरंभिकों को फ़ील्ड इनिशियलाइज़रों की तरह ही स्थिर भावों का मूल्यांकन करना चाहिए। यदि आपको गैर-स्थैतिक सदस्यों को संदर्भित करने की आवश्यकता है, तो आप या तो पहले की तरह निर्माणकर्ताओं में गुणों को शुरू कर सकते हैं, या अभिव्यक्ति-शरीर गुणों का उपयोग कर सकते हैं। गैर-स्थिर अभिव्यक्तियाँ, जैसे नीचे (टिप्पणी की गई), एक संकलक त्रुटि उत्पन्न करेगा:
// public decimal X { get; set; } = InitMe(); // generates compiler error
decimal InitMe() { return 4m; }
लेकिन ऑटो-प्रॉपर्टीज़ को इनिशियलाइज़ करने के लिए स्टैटिक मेथड्स का इस्तेमाल किया जा सकता है:
public class Rectangle
{
public double Length { get; set; } = 1;
public double Width { get; set; } = 1;
public double Area { get; set; } = CalculateArea(1, 1);
public static double CalculateArea(double length, double width)
{
return length * width;
}
}
यह विधि अलग-अलग स्तर के एक्सेसर्स वाले गुणों पर भी लागू की जा सकती है:
public short Type { get; private set; } = 15;
ऑटो-प्रॉपर्टी इनिशियलाइज़र सीधे उनके घोषणा के भीतर संपत्तियों के असाइनमेंट की अनुमति देता है। केवल-पढ़ने के गुणों के लिए, यह सुनिश्चित करने के लिए आवश्यक सभी आवश्यकताओं का ख्याल रखता है कि संपत्ति अपरिवर्तनीय है। उदाहरण के लिए, निम्न उदाहरण में FingerPrint
क्लास पर विचार करें:
public class FingerPrint
{
public DateTime TimeStamp { get; } = DateTime.UtcNow;
public string User { get; } =
System.Security.Principal.WindowsPrincipal.Current.Identity.Name;
public string Process { get; } =
System.Diagnostics.Process.GetCurrentProcess().ProcessName;
}
सावधान नोट
समान दिखने वाले के साथ नहीं भ्रमित ऑटो संपत्ति या क्षेत्र initializers करने पर ध्यान दें अभिव्यक्ति शरीर तरीकों जो का इस्तेमाल करते हैं =>
के रूप में करने का विरोध किया =
, और खेतों जो शामिल नहीं हैं { get; }
।
उदाहरण के लिए, निम्नलिखित घोषणाओं में से प्रत्येक अलग हैं।
public class UserGroupDto
{
// Read-only auto-property with initializer:
public ICollection<UserDto> Users1 { get; } = new HashSet<UserDto>();
// Read-write field with initializer:
public ICollection<UserDto> Users2 = new HashSet<UserDto>();
// Read-only auto-property with expression body:
public ICollection<UserDto> Users3 => new HashSet<UserDto>();
}
गुम { get; }
सार्वजनिक क्षेत्र में संपत्ति घोषणा परिणाम में। रीड-ओनली ऑटो-प्रॉपर्टी Users1
और रीड-राइट फील्ड Users2
को केवल एक बार इनिशियलाइज़ किया जाता है, लेकिन एक पब्लिक फील्ड क्लास के बाहर से कलेक्शन इंस्टेंस को बदलने की अनुमति देता है, जो आमतौर पर अवांछनीय होता है। एक्सप्रेशर के साथ केवल-पढ़ने के लिए केवल एक्सप्रेशन बॉडी वाले ऑटो-प्रॉपर्टी में बदलाव करने के लिए न केवल >
=>
से निकालना आवश्यक है, बल्कि इसे जोड़ना भी है { get; }
।
अलग प्रतीक ( =>
के बजाय =
में) Users3
संपत्ति के लिए प्रत्येक उपयोग में परिणाम का एक नया उदाहरण लौटने HashSet<UserDto>
जो है, जबकि वैध सी # (देखने के संकलक के दृष्टिकोण से) जब वांछित व्यवहार होने की संभावना नहीं है एक संग्रह सदस्य के लिए उपयोग किया जाता है।
उपरोक्त कोड इसके बराबर है:
public class UserGroupDto
{
// This is a property returning the same instance
// which was created when the UserGroupDto was instantiated.
private ICollection<UserDto> _users1 = new HashSet<UserDto>();
public ICollection<UserDto> Users1 { get { return _users1; } }
// This is a field returning the same instance
// which was created when the UserGroupDto was instantiated.
public virtual ICollection<UserDto> Users2 = new HashSet<UserDto>();
// This is a property which returns a new HashSet<UserDto> as
// an ICollection<UserDto> on each call to it.
public ICollection<UserDto> Users3 { get { return new HashSet<UserDto>(); } }
}
इंडेक्स इनिशियलाइज़र
इंडेक्स इनिशियलाइज़र एक ही समय में इंडेक्स के साथ ऑब्जेक्ट बनाना और इनिशियलाइज़ करना संभव बनाते हैं।
यह आरंभिक शब्दकोशों को बहुत आसान बनाता है:
var dict = new Dictionary<string, int>()
{
["foo"] = 34,
["bar"] = 42
};
किसी भी ऑब्जेक्ट जिसमें अनुक्रमित गेट्टर या सेटर का उपयोग इस सिंटैक्स के साथ किया जा सकता है:
class Program
{
public class MyClassWithIndexer
{
public int this[string index]
{
set
{
Console.WriteLine($"Index: {index}, value: {value}");
}
}
}
public static void Main()
{
var x = new MyClassWithIndexer()
{
["foo"] = 34,
["bar"] = 42
};
Console.ReadKey();
}
}
आउटपुट:
सूचकांक: फू, मूल्य: 34
सूचकांक: बार, मूल्य: 42
यदि कक्षा में कई अनुक्रमणिका हैं, तो उन सभी को बयानों के एक समूह में निर्दिष्ट करना संभव है:
class Program
{
public class MyClassWithIndexer
{
public int this[string index]
{
set
{
Console.WriteLine($"Index: {index}, value: {value}");
}
}
public string this[int index]
{
set
{
Console.WriteLine($"Index: {index}, value: {value}");
}
}
}
public static void Main()
{
var x = new MyClassWithIndexer()
{
["foo"] = 34,
["bar"] = 42,
[10] = "Ten",
[42] = "Meaning of life"
};
}
}
आउटपुट:
सूचकांक: फू, मूल्य: 34
सूचकांक: बार, मूल्य: 42
सूचकांक: 10, मूल्य: दस
सूचकांक: 42, मूल्य: जीवन का अर्थ
यह ध्यान दिया जाना चाहिए कि अनुक्रमणिका set
एक्सेसर एक Add
विधि (संग्रह आरंभीकरण में प्रयुक्त) की तुलना में अलग तरह से व्यवहार कर सकता है।
उदाहरण के लिए:
var d = new Dictionary<string, int>
{
["foo"] = 34,
["foo"] = 42,
}; // does not throw, second value overwrites the first one
बनाम:
var d = new Dictionary<string, int>
{
{ "foo", 34 },
{ "foo", 42 },
}; // run-time ArgumentException: An item with the same key has already been added.
स्ट्रिंग इंटरपोलेशन
स्ट्रिंग इंटरपोलेशन डेवलपर को स्ट्रिंग बनाने के लिए variables
और पाठ को संयोजित करने की अनुमति देता है।
मूल उदाहरण
दो int
वैरिएबल बनाए जाते हैं: foo
और bar
।
int foo = 34;
int bar = 42;
string resultString = $"The foo is {foo}, and the bar is {bar}.";
Console.WriteLine(resultString);
आउटपुट :
फू ल 34 है, और बार 42 है।
तार के भीतर ब्रेसिज़ का उपयोग अभी भी किया जा सकता है, जैसे:
var foo = 34;
var bar = 42;
// String interpolation notation (new style)
Console.WriteLine($"The foo is {{foo}}, and the bar is {{bar}}.");
यह निम्न आउटपुट का उत्पादन करता है:
फू {{फू} है, और बार {बार} है।
वर्बेटिम स्ट्रिंग शाब्दिक के साथ प्रक्षेप का उपयोग करना
स्ट्रिंग से पहले @
का उपयोग करने से स्ट्रिंग की व्याख्या शब्दशः होगी। इसलिए, जैसे यूनिकोड वर्ण या लाइन ब्रेक ठीक वैसे ही रहेंगे जैसे वे टाइप किए गए हैं। हालांकि, यह एक प्रक्षेपित स्ट्रिंग में भावों को प्रभावित नहीं करेगा जैसा कि निम्नलिखित उदाहरण में दिखाया गया है:
Console.WriteLine($@"In case it wasn't clear:
\u00B9
The foo
is {foo},
and the bar
is {bar}.");
आउटपुट: मामले में यह स्पष्ट नहीं था:
\ u00B9
द फू
34 है,
और बार
42 है।
भाव
स्ट्रिंग प्रक्षेप के साथ, घुंघराले ब्रेस {}
भीतर के भावों का भी मूल्यांकन किया जा सकता है। परिणाम स्ट्रिंग के भीतर संबंधित स्थान पर डाला जाएगा। उदाहरण के लिए, foo
और bar
की अधिकतम गणना करने और इसे सम्मिलित करने के लिए, कर्ली ब्रेस के भीतर Math.Max
उपयोग करें:
Console.WriteLine($"And the greater one is: { Math.Max(foo, bar) }");
आउटपुट:
और एक से अधिक है: 42
नोट: घुंघराले ब्रेस और अभिव्यक्ति के बीच किसी भी प्रमुख या अनुगामी व्हाट्सएप (स्पेस, टैब और CRLF / न्यूलाइन सहित) को पूरी तरह से नजरअंदाज किया जाता है और आउटपुट में शामिल नहीं किया जाता है
एक अन्य उदाहरण के रूप में, चर को मुद्रा के रूप में स्वरूपित किया जा सकता है:
Console.WriteLine($"Foo formatted as a currency to 4 decimal places: {foo:c4}");
आउटपुट:
फू को 4 दशमलव स्थानों पर मुद्रा के रूप में स्वरूपित किया गया: $ 34.0000
या उन्हें दिनांक के रूप में स्वरूपित किया जा सकता है:
Console.WriteLine($"Today is: {DateTime.Today:dddd, MMMM dd - yyyy}");
आउटपुट:
आज है: सोमवार, जुलाई, 20 - 2015
एक सशर्त (टर्नरी) ऑपरेटर वाले बयानों का मूल्यांकन प्रक्षेप के भीतर भी किया जा सकता है। हालाँकि, ये कोष्ठक में लिपटे होने चाहिए, क्योंकि बृहदान्त्र को अन्यथा ऊपर दिखाए गए स्वरूपण को इंगित करने के लिए उपयोग किया जाता है:
Console.WriteLine($"{(foo > bar ? "Foo is larger than bar!" : "Bar is larger than foo!")}");
आउटपुट:
बार फू से बड़ा है!
सशर्त अभिव्यक्ति और प्रारूप विनिर्देशक मिश्रित हो सकते हैं:
Console.WriteLine($"Environment: {(Environment.Is64BitProcess ? 64 : 32):00'-bit'} process");
आउटपुट:
पर्यावरण: 32-बिट प्रक्रिया
बच के क्रम
बैकस्लैश ( \
) और उद्धरण ( "
) अक्षर बचना, इंटरपोल किए गए स्ट्रिंग्स में ठीक वैसा ही काम करता है जैसा कि वर्बेटिम और नॉन-वर्बटीम स्ट्रिंग लिटरल दोनों के लिए होता है:
Console.WriteLine($"Foo is: {foo}. In a non-verbatim string, we need to escape \" and \\ with backslashes.");
Console.WriteLine($@"Foo is: {foo}. In a verbatim string, we need to escape "" with an extra quote, but we don't need to escape \");
आउटपुट:
फू 34 है। एक गैर-क्रियात्मक स्ट्रिंग में, हमें बैकस्लैश के साथ "और \" से बचने की आवश्यकता है।
फू 34 है। एक क्रिया स्ट्रिंग में, हमें "अतिरिक्त उद्धरण के साथ" भागने की आवश्यकता है, लेकिन हमें भागने की आवश्यकता नहीं है
प्रक्षेपित स्ट्रिंग में घुंघराले ब्रेस {
या }
शामिल करने के लिए, दो घुंघराले ब्रेसिज़ {{
या }}
:
$"{{foo}} is: {foo}"
आउटपुट:
{foo} है: 34
FormattableString प्रकार
$"..."
स्ट्रिंग प्रक्षेप अभिव्यक्ति का प्रकार हमेशा एक साधारण स्ट्रिंग नहीं होता है। संकलक तय करता है कि संदर्भ के आधार पर किस प्रकार का असाइन करना है:
string s = $"hello, {name}";
System.FormattableString s = $"Hello, {name}";
System.IFormattable s = $"Hello, {name}";
यह भी प्रकार की वरीयता का क्रम है जब कंपाइलर को चुनने की आवश्यकता होती है कि कौन सा अधिभार विधि कहा जा रहा है।
एक नया प्रकार , System.FormattableString
, स्वरूपित किए जाने वाले तर्कों के साथ एक समग्र प्रारूप स्ट्रिंग का प्रतिनिधित्व करता है। विशेष रूप से प्रक्षेप तर्कों को संभालने वाले अनुप्रयोगों को लिखने के लिए इसका उपयोग करें:
public void AddLogItem(FormattableString formattableString)
{
foreach (var arg in formattableString.GetArguments())
{
// do something to interpolation argument 'arg'
}
// use the standard interpolation and the current culture info
// to get an ordinary String:
var formatted = formattableString.ToString();
// ...
}
उपरोक्त विधि के साथ कॉल करें:
AddLogItem($"The foo is {foo}, and the bar is {bar}.");
उदाहरण के लिए, कोई स्ट्रिंग को स्वरूपित करने की प्रदर्शन लागत को नहीं चुन सकता है यदि लॉगिंग स्तर पहले से लॉग आइटम को फ़िल्टर करने के लिए जा रहा था। सम्यक रूपांतरण
प्रक्षेपित स्ट्रिंग से निहित प्रकार रूपांतरण हैं:
var s = $"Foo: {foo}";
System.IFormattable s = $"Foo: {foo}";
आप एक IFormattable
चर भी बना सकते हैं जो आपको स्ट्रिंग को अपरिवर्तनीय संदर्भ में बदलने की अनुमति देता है: var s = $"Bar: {bar}";
System.FormattableString s = $"Bar: {bar}";
वर्तमान और अपरिवर्तनीय संस्कृति विधियाँ
यदि कोड विश्लेषण चालू है, तो प्रक्षेपित तार सभी चेतावनी CA1305 ( IFormatProvider
निर्दिष्ट करें) का उत्पादन करेंगे। वर्तमान संस्कृति को लागू करने के लिए एक स्थिर विधि का उपयोग किया जा सकता है।
public static class Culture
{
public static string Current(FormattableString formattableString)
{
return formattableString?.ToString(CultureInfo.CurrentCulture);
}
public static string Invariant(FormattableString formattableString)
{
return formattableString?.ToString(CultureInfo.InvariantCulture);
}
}
फिर, वर्तमान संस्कृति के लिए एक सही स्ट्रिंग का उत्पादन करने के लिए, बस अभिव्यक्ति का उपयोग करें:
Culture.Current($"interpolated {typeof(string).Name} string.")
Culture.Invariant($"interpolated {typeof(string).Name} string.")
नोट: Current
और Invariant
है, क्योंकि डिफ़ॉल्ट रूप से, संकलक प्रदान करती टाइप विस्तार तरीके के रूप में नहीं बनाया जा सकता String
अंतर्वेशित स्ट्रिंग अभिव्यक्ति जो संकलित करने के लिए विफल निम्नलिखित कोड का कारण बनता है के लिए: $"interpolated {typeof(string).Name} string.".Current();
FormattableString
वर्ग में पहले से ही Invariant()
विधि FormattableString
, इसलिए FormattableString
using static
करने पर निर्भर FormattableString
Invariant()
कल्चर पर स्विच करने का सबसे सरल तरीका है:
using static System.FormattableString;
string invariant = Invariant($"Now = {DateTime.Now}"); string current = $"Now = {DateTime.Now}";
परदे के पीछे
Interpolated स्ट्रिंग्स सिर्फ String.Format()
लिए एक सिंटैक्टिक चीनी हैं। संकलक ( रोसलिन ) इसे एक String.Format
में बदल देगा। पर्दे के पीछे का भाग:
var text = $"Hello {name + lastName}";
ऊपर कुछ इस तरह से परिवर्तित किया जाएगा:
string text = string.Format("Hello {0}", new object[] {
name + lastName
});
स्ट्रिंग इंटरपोलेशन और लाइनक
आगे पठनीयता बढ़ाने के लिए Linq वक्तव्यों में प्रक्षेपित स्ट्रिंग्स का उपयोग करना संभव है।
var fooBar = (from DataRow x in fooBarTable.Rows
select string.Format("{0}{1}", x["foo"], x["bar"])).ToList();
के रूप में फिर से लिखा जा सकता है:
var fooBar = (from DataRow x in fooBarTable.Rows
select $"{x["foo"]}{x["bar"]}").ToList();
पुन: प्रयोज्य प्रक्षेपित स्ट्रिंग्स
string.Format
साथ, आप पुन: प्रयोज्य प्रारूप स्ट्रिंग्स बना सकते हैं:
public const string ErrorFormat = "Exception caught:\r\n{0}";
// ...
Logger.Log(string.Format(ErrorFormat, ex));
हालांकि, प्रक्षेपित तार गैर-मौजूद चर का संदर्भ देने वाले प्लेसहोल्डर्स के साथ संकलित नहीं करेंगे। निम्नलिखित संकलन नहीं होगा:
public const string ErrorFormat = $"Exception caught:\r\n{error}";
// CS0103: The name 'error' does not exist in the current context
इसके बजाय, एक Func<>
बनाएं जो चर खाए और एक String
लौटाए:
public static Func<Exception, string> FormatError =
error => $"Exception caught:\r\n{error}";
// ...
Logger.Log(FormatError(ex));
स्ट्रिंग प्रक्षेप और स्थानीयकरण
यदि आप अपने एप्लिकेशन को स्थानीयकृत कर रहे हैं तो आपको आश्चर्य हो सकता है कि क्या स्थानीयकरण के साथ-साथ स्ट्रिंग प्रक्षेप का उपयोग करना संभव है। वास्तव में, संसाधन फ़ाइलों में संग्रहीत करने की संभावना होना अच्छा होगा। String
एस:
"My name is {name} {middlename} {surname}"
बहुत कम पठनीय के बजाय: "My name is {0} {1} {2}"
String
प्रक्षेप प्रक्रिया संकलन समय पर होता है, साथ स्ट्रिंग स्वरूपण के विपरीत string.Format
जो क्रम पर होता है। एक प्रक्षेपित स्ट्रिंग में अभिव्यक्तियों को वर्तमान संदर्भ में नामों का संदर्भ देना चाहिए और संसाधन फ़ाइलों में संग्रहीत करने की आवश्यकता है। इसका मतलब है कि यदि आप स्थानीयकरण का उपयोग करना चाहते हैं तो आपको इसे करना होगा:
var FirstName = "John";
// method using different resource file "strings"
// for French ("strings.fr.resx"), German ("strings.de.resx"),
// and English ("strings.en.resx")
void ShowMyNameLocalized(string name, string middlename = "", string surname = "")
{
// get localized string
var localizedMyNameIs = Properties.strings.Hello;
// insert spaces where necessary
name = (string.IsNullOrWhiteSpace(name) ? "" : name + " ");
middlename = (string.IsNullOrWhiteSpace(middlename) ? "" : middlename + " ");
surname = (string.IsNullOrWhiteSpace(surname) ? "" : surname + " ");
// display it
Console.WriteLine($"{localizedMyNameIs} {name}{middlename}{surname}".Trim());
}
// switch to French and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
ShowMyNameLocalized(FirstName);
// switch to German and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
ShowMyNameLocalized(FirstName);
// switch to US English and greet John
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
ShowMyNameLocalized(FirstName);
यदि उपरोक्त भाषाओं के लिए संसाधन स्ट्रिंग व्यक्तिगत संसाधन फ़ाइलों में सही तरीके से संग्रहीत हैं, तो आपको निम्न आउटपुट प्राप्त करना चाहिए:
बॉनजोर, मोन नॉम एस्ट जॉन
हैलो, mein नाम ist जॉन
नमस्ते, मेरा नाम जॉन है
ध्यान दें कि इसका अर्थ है कि नाम हर भाषा में स्थानीय स्ट्रिंग का अनुसरण करता है। अगर ऐसा नहीं है, तो आपको प्लेसहोल्डर्स को संसाधन स्ट्रिंग्स में जोड़ने और फ़ंक्शन को ऊपर संशोधित करने की आवश्यकता है या आपको फ़ंक्शन में संस्कृति जानकारी को क्वेरी करने और विभिन्न मामलों वाले स्विच केस स्टेटमेंट प्रदान करने की आवश्यकता है। संसाधन फ़ाइलों के बारे में अधिक जानकारी के लिए, C # में स्थानीयकरण का उपयोग कैसे करें देखें।
डिफ़ॉल्ट फ़ॉलबैक भाषा का उपयोग करना एक अच्छा अभ्यास है जिसे ज्यादातर लोग समझ पाएंगे, यदि कोई अनुवाद उपलब्ध नहीं है। मैं अंग्रेज़ी को डिफ़ॉल्ट फ़ॉलबैक भाषा के रूप में उपयोग करने का सुझाव देता हूं।
पुनरावर्ती प्रक्षेप
हालांकि बहुत उपयोगी नहीं है, यह एक दूसरे के घुंघराले कोष्ठक के अंदर पुन: प्रक्षेपित string
का उपयोग करने की अनुमति है:
Console.WriteLine($"String has {$"My class is called {nameof(MyClass)}.".Length} chars:");
Console.WriteLine($"My class is called {nameof(MyClass)}.");
आउटपुट:
स्ट्रिंग में 27 वर्ण हैं:
मेरी कक्षा को MyClass कहा जाता है।
पकड़ में और आखिर में इंतजार
यह उपयोग करना संभव है await
अभिव्यक्ति लागू करने के लिए इंतजार ऑपरेटर के लिए कार्य या कार्य (TResult के) में catch
और finally
सी # 6 में ब्लॉक।
संकलक सीमाओं के कारण पहले के संस्करणों में catch
और finally
ब्लॉक में await
अभिव्यक्ति का उपयोग करना संभव नहीं था। C # 6 await
अभिव्यक्ति की अनुमति देकर एसिंक्स कार्यों को बहुत आसान बनाता है।
try
{
//since C#5
await service.InitializeAsync();
}
catch (Exception e)
{
//since C#6
await logger.LogAsync(e);
}
finally
{
//since C#6
await service.CloseAsync();
}
एक bool
का उपयोग करने के लिए या async संचालन करने के लिए कैच पकड़ने के बाहर Exception
घोषणा करने के लिए C # 5 में इसकी आवश्यकता थी। इस विधि को निम्न उदाहरण में दिखाया गया है:
bool error = false;
Exception ex = null;
try
{
// Since C#5
await service.InitializeAsync();
}
catch (Exception e)
{
// Declare bool or place exception inside variable
error = true;
ex = e;
}
// If you don't use the exception
if (error)
{
// Handle async task
}
// If want to use information from the exception
if (ex != null)
{
await logger.LogAsync(e);
}
// Close the service, since this isn't possible in the finally
await service.CloseAsync();
अशक्त प्रचार
द ?.
ऑपरेटर और ?[...]
ऑपरेटर को नल-सशर्त ऑपरेटर कहा जाता है। इसे कभी-कभी अन्य नामों से भी संदर्भित किया जाता है जैसे कि सुरक्षित नेविगेशन ऑपरेटर ।
यह उपयोगी है, क्योंकि यदि .
(सदस्य एक्सेसर) ऑपरेटर को एक अभिव्यक्ति पर लागू किया जाता है जो null
करने के लिए मूल्यांकन करता है, कार्यक्रम NullReferenceException
को फेंक देगा। डेवलपर के बजाय का उपयोग करता है ?.
(नल-सशर्त) ऑपरेटर, अभिव्यक्ति एक अपवाद को फेंकने के बजाय अशक्त करने के लिए मूल्यांकन करेगा।
ध्यान दें कि यदि ?.
ऑपरेटर का उपयोग किया जाता है और अभिव्यक्ति गैर-अशक्त है ?.
और .
समतुल्य हैं।
मूल बातें
var teacherName = classroom.GetTeacher().Name;
// throws NullReferenceException if GetTeacher() returns null
यदि classroom
शिक्षक नहीं है, तो GetTeacher()
null
हो सकता है। जब यह null
और Name
गुण तक पहुँच है, तो एक NullReferenceException
को फेंक दिया जाएगा।
यदि हम इस कथन का उपयोग करने के लिए संशोधित करते हैं ?.
वाक्यविन्यास, संपूर्ण अभिव्यक्ति का परिणाम null
होगा:
var teacherName = classroom.GetTeacher()?.Name;
// teacherName is null if GetTeacher() returns null
इसके बाद, यदि classroom
भी null
हो सकती है, तो हम इस कथन को भी लिख सकते हैं:
var teacherName = classroom?.GetTeacher()?.Name;
// teacherName is null if GetTeacher() returns null OR classroom is null
यह शॉर्ट-सर्किटिंग का एक उदाहरण है: जब नल-सशर्त ऑपरेटर का उपयोग करने वाला कोई भी सशर्त एक्सेस ऑपरेशन शून्य का मूल्यांकन करता है, तो पूरी अभिव्यक्ति तुरंत शून्य का मूल्यांकन करती है, बाकी श्रृंखला को संसाधित किए बिना।
जब Nullable<T>
सशर्त ऑपरेटर वाली अभिव्यक्ति का टर्मिनल सदस्य मान प्रकार का होता है, तो अभिव्यक्ति उस प्रकार के Nullable<T>
का मूल्यांकन करती है और इसलिए इसे बिना अभिव्यक्ति के प्रत्यक्ष प्रतिस्थापन के रूप में उपयोग नहीं किया जा सकता है ?.
।
bool hasCertification = classroom.GetTeacher().HasCertification;
// compiles without error but may throw a NullReferenceException at runtime
bool hasCertification = classroom?.GetTeacher()?.HasCertification;
// compile time error: implicit conversion from bool? to bool not allowed
bool? hasCertification = classroom?.GetTeacher()?.HasCertification;
// works just fine, hasCertification will be null if any part of the chain is null
bool hasCertification = classroom?.GetTeacher()?.HasCertification.GetValueOrDefault();
// must extract value from nullable to assign to a value type variable
Null-Coalescing Operator (??) के साथ प्रयोग करें
आप अशक्त-संचालक ऑपरेटर को Null-coalescing Operator ( ??
) के साथ जोड़ सकते हैं यदि अभिव्यक्ति null
तो एक डिफ़ॉल्ट मान वापस करने के लिए। ऊपर हमारे उदाहरण का उपयोग करना:
var teacherName = classroom?.GetTeacher()?.Name ?? "No Name";
// teacherName will be "No Name" when GetTeacher()
// returns null OR classroom is null OR Name is null
इंडेक्सर्स के साथ प्रयोग करें
अशक्त संचालक को अनुक्रमणिका के साथ प्रयोग किया जा सकता है:
var firstStudentName = classroom?.Students?[0]?.Name;
उपरोक्त उदाहरण में:
- पहला
?.
यह सुनिश्चित करता है किclassroom
null
नहीं है। - दूसरा
?
यह सुनिश्चित करता है कि संपूर्णStudents
संग्रहnull
नहीं है। - तीसरा
?.
अनुक्रमणिका सुनिश्चित करने के बाद कि[0]
अनुक्रमणिका एकnull
वस्तु नहीं लौटाती है। यह ध्यान दिया जाना चाहिए कि यह ऑपरेशन अभी भी एकIndexOutOfRangeException
फेंक सकता है।
शून्य कार्यों के साथ प्रयोग करें
शून्य-सशर्त ऑपरेटर का उपयोग void
कार्यों के साथ भी किया जा सकता है। हालांकि इस मामले में, बयान null
मूल्यांकन नहीं करेगा। यह सिर्फ एक NullReferenceException
रोक देगा।
List<string> list = null;
list?.Add("hi"); // Does not evaluate to null
ईवेंट आमंत्रण के साथ उपयोग करें
निम्नलिखित घटना की परिभाषा मानते हुए:
private event EventArgs OnCompleted;
जब कोई ईवेंट लागू, पारंपरिक रूप से, यह करता है, तो घटना की जाँच करने के लिए सबसे अच्छा अभ्यास है null
मामले में कोई भी सदस्य नहीं मौजूद हैं:
var handler = OnCompleted;
if (handler != null)
{
handler(EventArgs.Empty);
}
चूंकि अशक्त-संचालक को पेश किया गया है, इसलिए आह्वान को एक पंक्ति में घटाया जा सकता है:
OnCompleted?.Invoke(EventArgs.Empty);
सीमाएं
अशक्त-संचालक परिचालक उत्पन्न करता है, लैवल्यू नहीं, अर्थात इसका उपयोग संपत्ति असाइनमेंट, ईवेंट सब्सक्रिप्शन आदि के लिए नहीं किया जा सकता है। उदाहरण के लिए, निम्न कोड काम नहीं करेगा:
// Error: The left-hand side of an assignment must be a variable, property or indexer
Process.GetProcessById(1337)?.EnableRaisingEvents = true;
// Error: The event can only appear on the left hand side of += or -=
Process.GetProcessById(1337)?.Exited += OnProcessExited;
gotchas
ध्यान दें कि:
int? nameLength = person?.Name.Length; // safe if 'person' is null
के रूप में ही नहीं है:
int? nameLength = (person?.Name).Length; // avoid this
क्योंकि पूर्व से मेल खाती है:
int? nameLength = person != null ? (int?)person.Name.Length : null;
और बाद वाले से मेल खाती है:
int? nameLength = (person != null ? person.Name : null).Length;
त्रिगुट ऑपरेटर के बावजूद ?:
यहाँ दो मामलों के बीच अंतर को स्पष्ट करने के लिए प्रयोग किया जाता है, इन ऑपरेटरों नहीं के बराबर हैं। यह निम्नलिखित उदाहरण के साथ आसानी से प्रदर्शित किया जा सकता है:
void Main()
{
var foo = new Foo();
Console.WriteLine("Null propagation");
Console.WriteLine(foo.Bar?.Length);
Console.WriteLine("Ternary");
Console.WriteLine(foo.Bar != null ? foo.Bar.Length : (int?)null);
}
class Foo
{
public string Bar
{
get
{
Console.WriteLine("I was read");
return string.Empty;
}
}
}
कौन से आउटपुट:
अशक्त प्रसार
मैंने पढ़ा था
0
त्रिगुट
मैंने पढ़ा था
मैंने पढ़ा था
0
कई आक्रमणों से बचने के लिए समतुल्य होगा:
var interimResult = foo.Bar;
Console.WriteLine(interimResult != null ? interimResult.Length : (int?)null);
और यह अंतर कुछ हद तक बताता है कि क्यों अभिव्यक्ति के पेड़ों में अशक्त प्रसार संचालक अभी तक समर्थित नहीं है ।
स्थिर प्रकार का उपयोग करना
using static [Namespace.Type]
निर्देश का using static [Namespace.Type]
प्रकारों और गणना मूल्यों के स्थिर सदस्यों के आयात की अनुमति मिलती है। एक्सटेंशन विधियों को एक्सटेंशन विधियों (केवल एक प्रकार से) के रूप में आयात किया जाता है, शीर्ष-स्तरीय दायरे में नहीं।
using static System.Console;
using static System.ConsoleColor;
using static System.Math;
class Program
{
static void Main()
{
BackgroundColor = DarkBlue;
WriteLine(Sqrt(2));
}
}
using System;
class Program
{
static void Main()
{
Console.BackgroundColor = ConsoleColor.DarkBlue;
Console.WriteLine(Math.Sqrt(2));
}
}
बेहतर अधिभार संकल्प
स्निपेट के बाद एक प्रतिनिधि (उम्मीद के मुताबिक मेमने के विपरीत) एक विधि समूह को पारित करने का एक उदाहरण दिखाता है। ओवरलोड रिज़ॉल्यूशन अब C # 6 की क्षमता के कारण अस्पष्ट ओवरलोड त्रुटि को बढ़ाने के बजाय इसे हल कर देगा जो कि पारित किए गए तरीके की वापसी प्रकार की जांच करने के लिए है।
using System;
public class Program
{
public static void Main()
{
Overloaded(DoSomething);
}
static void Overloaded(Action action)
{
Console.WriteLine("overload with action called");
}
static void Overloaded(Func<int> function)
{
Console.WriteLine("overload with Func<int> called");
}
static int DoSomething()
{
Console.WriteLine(0);
return 0;
}
}
परिणाम:
त्रुटि
त्रुटि CS0121: कॉल निम्न विधियों या गुणों के बीच अस्पष्ट है: 'Program.Overloaded (System.Action)' और 'Program.Overloaded (System.Func)'
C # 6 अच्छी तरह से लैम्ब्डा अभिव्यक्ति के लिए सटीक मिलान के निम्नलिखित मामले को भी संभाल सकता है जिसके परिणामस्वरूप C # 5 में त्रुटि हुई होगी।
using System;
class Program
{
static void Foo(Func<Func<long>> func) {}
static void Foo(Func<Func<int>> func) {}
static void Main()
{
Foo(() => () => 7);
}
}
मामूली परिवर्तन और बगफिक्स
कोष्ठक अब नामित मापदंडों के आसपास निषिद्ध हैं। निम्नलिखित C # 5 में संकलित है, लेकिन C # 6 नहीं
Console.WriteLine((value: 23));
की ऑपरेंड is
और as
नहीं रह गया है विधि समूहों होने की अनुमति दी जाती है। निम्नलिखित C # 5 में संकलित है, लेकिन C # 6 नहीं
var result = "".Any is byte;
देशी संकलक ने इसकी अनुमति दी (हालांकि यह एक चेतावनी दिखाती है), और वास्तव में विस्तार विधि संगतता की जांच भी नहीं की,
1.Any is string
जैसे पागल चीजों को अनुमति देता1.Any is string
याIDisposable.Dispose is object
।
परिवर्तनों पर अपडेट के लिए यह संदर्भ देखें।
संग्रह आरंभीकरण के लिए एक विस्तार विधि का उपयोग करना
संग्रह आरंभीकरण वाक्यविन्यास का उपयोग तब किया जा सकता है जब किसी भी वर्ग को त्वरित किया जाता है जो IEnumerable
लागू करता है और Add
नामक एक विधि है जो एक एकल पैरामीटर लेता है।
पिछले संस्करणों में, इस Add
मेथड को इनिशियलाइज़ होने वाले क्लास पर एक इंस्टेंस मेथड होना था। C # 6 में, यह एक विस्तार विधि भी हो सकती है।
public class CollectionWithAdd : IEnumerable
{
public void Add<T>(T item)
{
Console.WriteLine("Item added with instance add method: " + item);
}
public IEnumerator GetEnumerator()
{
// Some implementation here
}
}
public class CollectionWithoutAdd : IEnumerable
{
public IEnumerator GetEnumerator()
{
// Some implementation here
}
}
public static class Extensions
{
public static void Add<T>(this CollectionWithoutAdd collection, T item)
{
Console.WriteLine("Item added with extension add method: " + item);
}
}
public class Program
{
public static void Main()
{
var collection1 = new CollectionWithAdd{1,2,3}; // Valid in all C# versions
var collection2 = new CollectionWithoutAdd{4,5,6}; // Valid only since C# 6
}
}
यह आउटपुट होगा:
मद उदाहरण के साथ जोड़ा विधि: 1
उदाहरण जोड़ विधि के साथ जोड़ा गया आइटम: 2
उदाहरण जोड़ विधि के साथ जोड़ा गया आइटम: 3
एक्सटेंशन जोड़ विधि के साथ जोड़ा गया आइटम: 4
एक्सटेंशन जोड़ें विधि के साथ जोड़ा गया आइटम: 5
एक्सटेंशन जोड़ विधि के साथ जोड़ा गया आइटम: 6
चेतावनियों को बढ़ाने में अक्षम करें
C # 5.0 और इससे पहले के डेवलपर केवल संख्याओं द्वारा चेतावनी को दबा सकते थे। रोसलिन एनालाइज़र की शुरूआत के साथ, सी # को विशिष्ट पुस्तकालयों से जारी चेतावनियों को अक्षम करने का एक तरीका चाहिए। सी # 6.0 के साथ प्रज्ञा निर्देश नाम से चेतावनियों को दबा सकता है।
इससे पहले:
#pragma warning disable 0501
सी # 6.0:
#pragma warning disable CS0501