खोज…


परिचय

C # 7.0 C # का सातवाँ संस्करण है। इस संस्करण में कुछ नई विशेषताएं शामिल हैं: ट्यूपल्स के लिए भाषा समर्थन, स्थानीय फ़ंक्शन, out var घोषणाएं, अंक विभाजक, बाइनरी शाब्दिक, पैटर्न मिलान, फेंक अभिव्यक्ति, ref return और ref local और विस्तारित अभिव्यक्ति शारीरिक सदस्य सूची।

आधिकारिक संदर्भ: C # 7 में नया क्या है

var घोषणा

C # में एक सामान्य पैटर्न bool TryParse(object input, out object value) को सुरक्षित रूप से पार्स करने के लिए bool TryParse(object input, out object value) का उपयोग कर रहा है।

पठनीयता को बेहतर बनाने के लिए out var घोषणा एक सरल विशेषता है। यह एक चर को उसी समय घोषित करने की अनुमति देता है जब इसे आउट पैरामीटर के रूप में पारित किया जाता है।

इस तरह घोषित किया गया एक चर उस बिंदु पर शरीर के शेष भाग में स्कोप किया जाता है।

उदाहरण

C # 7.0 से पहले TryParse का उपयोग करते हुए, आपको फ़ंक्शन को कॉल करने से पहले मान प्राप्त करने के लिए एक चर घोषित करना होगा:

7.0
int value;
if (int.TryParse(input, out value)) 
{
    Foo(value); // ok
}
else
{
    Foo(value); // value is zero
}

Foo(value); // ok

C # 7.0 में, आप एक अलग पैरामीटर की घोषणा की आवश्यकता को समाप्त करते हुए, out पैरामीटर को पारित चर की घोषणा को इनलाइन कर सकते हैं:

7.0
if (int.TryParse(input, out var value)) 
{
    Foo(value); // ok
}
else
{
    Foo(value); // value is zero
}

Foo(value); // still ok, the value in scope within the remainder of the body

यदि कुछ पैरामीटर जो फ़ंक्शन वापस करता है, out आवश्यक नहीं है कि आप त्याग ऑपरेटर _ उपयोग कर सकते हैं।

p.GetCoordinates(out var x, out _); // I only care about x

एक out var घोषणा जो पहले से ही है किसी भी मौजूदा समारोह के साथ इस्तेमाल किया जा सकता out मानकों। फ़ंक्शन डिक्लेरेशन सिंटैक्स समान रहता है, और फ़ंक्शन को एक out var घोषणा के साथ संगत बनाने के लिए कोई अतिरिक्त आवश्यकताओं की आवश्यकता नहीं होती है। यह सुविधा केवल वाक्य रचना चीनी है।

out var घोषणा की एक और विशेषता यह है कि इसका उपयोग अनाम प्रकारों के साथ किया जा सकता है।

7.0
var a = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var groupedByMod2 = a.Select(x => new
                                  {
                                      Source = x,
                                      Mod2 = x % 2
                                  })
                     .GroupBy(x => x.Mod2)
                     .ToDictionary(g => g.Key, g => g.ToArray());
if (groupedByMod2.TryGetValue(1, out var oddElements))
{
    Console.WriteLine(oddElements.Length);
}

इस कोड में हम एक बनाने के Dictionary के साथ int कुंजी और अनाम प्रकार मान की सरणी। C # के पिछले संस्करण में यहाँ TryGetValue पद्धति का उपयोग करना असंभव था क्योंकि इसके लिए आपको out वेरिएबल घोषित करने की आवश्यकता थी (जो कि गुमनाम प्रकार का है!)। हालांकि, out var साथ हमें out चर के प्रकार को स्पष्ट रूप से निर्दिष्ट करने की आवश्यकता नहीं है।

सीमाएं

ध्यान दें कि बाहर की घोषणाएं LINQ प्रश्नों में सीमित उपयोग की हैं क्योंकि अभिव्यक्ति को लैम्ब्डा निकायों के रूप में व्याख्या की जाती है, इसलिए शुरू किए गए चर का दायरा इन लंबों तक सीमित है। उदाहरण के लिए, निम्न कोड काम नहीं करेगा:

var nums = 
    from item in seq
    let success = int.TryParse(item, out var tmp)
    select success ? tmp : 0; // Error: The name 'tmp' does not exist in the current context

संदर्भ

बाइनरी लिटरल

बाइनरी लीटरल्स का प्रतिनिधित्व करने के लिए 0b उपसर्ग का उपयोग किया जा सकता है।

द्विआधारी शाब्दिक शून्य और लोगों से संख्याओं के निर्माण की अनुमति देता है, जो यह देखता है कि कौन से बिट्स संख्या के बाइनरी प्रतिनिधित्व में बहुत आसान हैं। यह बाइनरी फ्लैग के साथ काम करने के लिए उपयोगी हो सकता है।

निम्नलिखित एक निर्दिष्ट करने के बराबर तरीके हैं int मान के साथ 34 (= 2 5 + 2 1):

// Using a binary literal:
//   bits: 76543210
int a1 = 0b00100010;          // binary: explicitly specify bits

// Existing methods:
int a2 = 0x22;                // hexadecimal: every digit corresponds to 4 bits
int a3 = 34;                  // decimal: hard to visualise which bits are set
int a4 = (1 << 5) | (1 << 1); // bitwise arithmetic: combining non-zero bits

झंडों की झांकियां

इससे पहले, इस उदाहरण में तीन तरीकों में से एक का उपयोग करके केवल enum लिए ध्वज मान निर्दिष्ट किया जा सकता है:

[Flags]
public enum DaysOfWeek
{
    // Previously available methods:
    //          decimal        hex       bit shifting
    Monday    =  1,    //    = 0x01    = 1 << 0
    Tuesday   =  2,    //    = 0x02    = 1 << 1
    Wednesday =  4,    //    = 0x04    = 1 << 2
    Thursday  =  8,    //    = 0x08    = 1 << 3
    Friday    = 16,    //    = 0x10    = 1 << 4
    Saturday  = 32,    //    = 0x20    = 1 << 5
    Sunday    = 64,    //    = 0x40    = 1 << 6

    Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday,
    Weekends = Saturday | Sunday
}

द्विआधारी शाब्दिक के साथ यह अधिक स्पष्ट है कि कौन से बिट्स सेट हैं, और उनका उपयोग करने के लिए हेक्साडेसिमल संख्या और बिटवाइज़ अंकगणित को समझने की आवश्यकता नहीं है:

[Flags]
public enum DaysOfWeek
{
    Monday    = 0b00000001,
    Tuesday   = 0b00000010,
    Wednesday = 0b00000100,
    Thursday  = 0b00001000,
    Friday    = 0b00010000,
    Saturday  = 0b00100000,
    Sunday    = 0b01000000,

    Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday,
    Weekends = Saturday | Sunday
}

अंक विभाजक

अंडरस्कोर _ का उपयोग अंकों के विभाजक के रूप में किया जा सकता है। बड़े संख्यात्मक अंकों में समूह अंकों में सक्षम होने से पठनीयता पर महत्वपूर्ण प्रभाव पड़ता है।

नीचे दिए गए को छोड़कर, एक अंकीय शाब्दिक में अंडरस्कोर कहीं भी हो सकता है। अलग-अलग समूह अलग-अलग परिदृश्यों में या अलग-अलग संख्यात्मक आधारों के साथ समझ बना सकते हैं।

अंकों के किसी भी क्रम को एक या अधिक अंडरस्कोर द्वारा अलग किया जा सकता है। _ दशमलव में और साथ ही घातांक में अनुमति है। विभाजकों का कोई अर्थ प्रभाव नहीं है - उन्हें बस अनदेखा किया जाता है।

int bin = 0b1001_1010_0001_0100;
int hex = 0x1b_a0_44_fe;
int dec = 33_554_432;
int weird = 1_2__3___4____5_____6______7_______8________9;
double real = 1_000.111_1e-1_000;

जहाँ _ अंक विभाजक का उपयोग नहीं किया जा सकता है:

  • मूल्य की शुरुआत में ( _121 )
  • मूल्य के अंत में ( 121_ या 121.05_ )
  • दशमलव के आगे ( 10_.0 )
  • प्रतिपादक वर्ण के आगे ( 1.1e_1 )
  • विशिष्ट प्रकार के आगे ( 10_f )
  • बाइनरी और हेक्साडेसिमल शाब्दिक में 0x या 0b तुरंत बाद ( उदाहरण के लिए 0b_1002-2000 ) की अनुमति दी जा सकती है

टुपल्स के लिए भाषा समर्थन

मूल बातें

टपल एक आदेशित, तत्वों की परिमित सूची है। ट्यूपल को सामान्यतः एक एकल इकाई के साथ काम करने के साधन के रूप में उपयोग किया जाता है जो कि व्यक्तिगत रूप से टपल के प्रत्येक तत्व के साथ काम करने के बजाय सामूहिक रूप से काम करता है, और एक संबंधपरक डेटाबेस में व्यक्तिगत पंक्तियों (यानी "रिकॉर्ड") का प्रतिनिधित्व करता है।

C # 7.0 में, विधियों में कई रिटर्न मान हो सकते हैं। पर्दे के पीछे, कंपाइलर नई वैल्यूटल संरचना का उपयोग करेगा।

public (int sum, int count) GetTallies() 
{
    return (1, 2);
}

साइड नोट : इसके लिए Visual Studio 2017 में काम करने के लिए, आपको System.ValueTuple पैकेज प्राप्त करना होगा।

यदि एक टपल-रिटर्निंग विधि परिणाम एक एकल चर को सौंपा गया है, तो आप विधि हस्ताक्षर पर उनके परिभाषित नामों से सदस्यों तक पहुँच सकते हैं:

var result = GetTallies();
// > result.sum
// 1
// > result.count
// 2

टुपल डिकंस्ट्रक्शन

टपल डीकंस्ट्रक्शन एक टपल को उसके भागों में अलग करता है।

उदाहरण के लिए, GetTallies आह्वान GetTallies और दो अलग-अलग वेरिएबल्स में रिटर्न वैल्यू को असाइन करना उन दो वेरिएबल्स में टपल को GetTallies करता है:

(int tallyOne, int tallyTwo) = GetTallies();

var भी काम करता है:

(var s, var c) = GetTallies();

आप () बाहर वाले var साथ छोटे वाक्यविन्यास का भी उपयोग कर सकते हैं:

var (s, c) = GetTallies();

आप मौजूदा चर में भी विघटित कर सकते हैं:

int s, c;
(s, c) = GetTallies();

स्वैपिंग अब बहुत सरल है (कोई अस्थायी चर की आवश्यकता नहीं):

(b, a) = (a, b);

दिलचस्प बात यह है कि किसी भी वस्तु को कक्षा में एक Deconstruct विधि को परिभाषित करने से बाधित किया जा सकता है:

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public void Deconstruct(out string firstName, out string lastName)
    {
        firstName = FirstName;
        lastName = LastName;
    }
}

var person = new Person { FirstName = "John", LastName = "Smith" };
var (localFirstName, localLastName) = person;

इस स्थिति में, (localFirstName, localLastName) = person सिंटैक्स (localFirstName, localLastName) = person पर Deconstruct को लागू कर रहा person

Deconstruction को एक विस्तार विधि में भी परिभाषित किया जा सकता है। यह उपरोक्त के बराबर है:

public static class PersonExtensions
{
    public static void Deconstruct(this Person person, out string firstName, out string lastName)
    {
        firstName = person.FirstName;
        lastName = person.LastName;
    }
}

var (localFirstName, localLastName) = person;

Person वर्ग के लिए एक वैकल्पिक दृष्टिकोण Name ही एक Tuple रूप में परिभाषित करना है। निम्नलिखित को धयान मे रखते हुए:

class Person
{
    public (string First, string Last) Name { get; }

    public Person((string FirstName, string LastName) name)
    {
        Name = name;
    }
}

तब आप किसी व्यक्ति को इस तरह से रोक सकते हैं (जहां हम एक तर्क के रूप में एक टपल ले सकते हैं):

var person = new Person(("Jane", "Smith"));

var firstName = person.Name.First; // "Jane"
var lastName = person.Name.Last;   // "Smith"

टुपल इनिशियलाइज़ेशन

तुम भी मनमाने ढंग से कोड में tuples बना सकते हैं:

var name = ("John", "Smith");
Console.WriteLine(name.Item1);
// Outputs John

Console.WriteLine(name.Item2);
// Outputs Smith

टपल बनाते समय, आप tuple के सदस्यों के लिए तदर्थ आइटम के नाम निर्दिष्ट कर सकते हैं:

var name = (first: "John", middle: "Q", last: "Smith");
Console.WriteLine(name.first);
// Outputs John

प्रकार का अनुमान

एक ही हस्ताक्षर (मिलान प्रकार और गिनती) के साथ परिभाषित कई ट्यूपल मिलान प्रकार के रूप में अनुमान लगाए जाएंगे। उदाहरण के लिए:

public (int sum, double average) Measure(List<int> items)
{
    var stats = (sum: 0, average: 0d);
    stats.sum = items.Sum();
    stats.average = items.Average();
    return stats;
}

stats वापस किया जा सकता के बाद से की घोषणा stats चर और विधि की वापसी हस्ताक्षर एक मैच कर रहे हैं।

परावर्तन और टपल फील्ड नाम

सदस्य नाम रनटाइम पर मौजूद नहीं हैं। परावर्तन एक ही संख्या और सदस्यों के प्रकार के साथ tuples पर विचार करेगा, भले ही सदस्य के नाम मेल न खाते हों। एक टुपल को एक object बदलना और फिर एक ही सदस्य प्रकारों के साथ एक टपल में, लेकिन अलग-अलग नामों से, एक अपवाद का कारण नहीं होगा।

जबकि ValueTuple वर्ग स्वयं सदस्य नामों के लिए जानकारी संरक्षित नहीं करता है, लेकिन जानकारी TupleElementNamesAttribute में प्रतिबिंब के माध्यम से उपलब्ध है। यह विशेषता टूप्ले पर ही लागू नहीं होती है, बल्कि मापदंडों, रिटर्न वैल्यू, प्रॉपर्टीज और फील्ड्स पर लागू होती है। यह ट्यूपल आइटम नामों को असेंबली में संरक्षित रखने की अनुमति देता है अर्थात यदि कोई विधि रिटर्न (स्ट्रिंग नाम, इंट काउंट) नाम का नाम और गणना किसी अन्य असेंबली में विधि के कॉल करने वालों के लिए उपलब्ध होगी क्योंकि रिटर्न वैल्यू को TupleElementName के साथ चिह्नित किया जाएगा। "नाम" और "गणना"।

जेनरिक और async साथ प्रयोग करें

नई टपल सुविधाएँ (अंतर्निहित ValueTuple प्रकार का उपयोग करके) पूरी तरह से जेनरिक का समर्थन करती हैं और इसे सामान्य प्रकार के पैरामीटर के रूप में इस्तेमाल किया जा सकता है। यह async / await पैटर्न के साथ उनका उपयोग करना संभव बनाता है:

public async Task<(string value, int count)> GetValueAsync()
{
    string fooBar = await _stackoverflow.GetStringAsync();
    int num = await _stackoverflow.GetIntAsync();

    return (fooBar, num);
}

संग्रह के साथ प्रयोग करें

यह एक उदाहरण के रूप में (उदाहरण के रूप में) में एक tuples का संग्रह होना फायदेमंद हो सकता है जहाँ आप कोड ब्रांचिंग से बचने के लिए शर्तों के आधार पर एक मिलान tuple खोजने का प्रयास कर रहे हैं।

उदाहरण:

private readonly List<Tuple<string, string, string>> labels = new List<Tuple<string, string, string>>()
{
    new Tuple<string, string, string>("test1", "test2", "Value"),
    new Tuple<string, string, string>("test1", "test1", "Value2"),
    new Tuple<string, string, string>("test2", "test2", "Value3"),
};

public string FindMatchingValue(string firstElement, string secondElement)
{
    var result = labels
        .Where(w => w.Item1 == firstElement && w.Item2 == secondElement)
        .FirstOrDefault();

    if (result == null)
        throw new ArgumentException("combo not found");

    return result.Item3;
}

नए tuples के साथ बन सकता है:

private readonly List<(string firstThingy, string secondThingyLabel, string foundValue)> labels = new List<(string firstThingy, string secondThingyLabel, string foundValue)>()
{
    ("test1", "test2", "Value"),
    ("test1", "test1", "Value2"),
    ("test2", "test2", "Value3"),
}

public string FindMatchingValue(string firstElement, string secondElement)
{
    var result = labels
        .Where(w => w.firstThingy == firstElement && w.secondThingyLabel == secondElement)
        .FirstOrDefault();

    if (result == null)
        throw new ArgumentException("combo not found");

    return result.foundValue;
}

यद्यपि ऊपर दिए गए उदाहरण के नामकरण पर नामकरण बहुत सामान्य है, प्रासंगिक लेबल का विचार "आइटम 1", "आइटम 2" और "आइटम 3" के संदर्भ में कोड में क्या प्रयास किया जा रहा है, इसकी गहरी समझ के लिए अनुमति देता है।

ValueTuple और Tuple के बीच अंतर

ValueTuple शुरूआत का प्राथमिक कारण प्रदर्शन है।

नाम लिखो ValueTuple Tuple
वर्ग या संरचना struct class
उत्परिवर्तन (निर्माण के बाद बदलते मूल्य) परिवर्तनशील अडिग
नामित सदस्यों और अन्य भाषा समर्थन करते हैं हाँ नहीं ( TBD )

संदर्भ

स्थानीय कार्य

स्थानीय कार्य एक विधि के भीतर परिभाषित किए गए हैं और इसके बाहर उपलब्ध नहीं हैं। उनके पास सभी स्थानीय चर हैं और पुनरावृत्तियों, async / await और लंबोदर सिंटैक्स का समर्थन करते हैं। इस तरह, एक फ़ंक्शन के लिए विशिष्ट पुनरावृत्ति वर्ग को भीड़ के बिना कार्यात्मक किया जा सकता है। साइड इफेक्ट के रूप में, यह अंतर्मुखी सुझाव प्रदर्शन में सुधार करता है।

उदाहरण

double GetCylinderVolume(double radius, double height)
{
    return getVolume();

    double getVolume()
    {
        // You can declare inner-local functions in a local function 
        double GetCircleArea(double r) => Math.PI * r * r;

        // ALL parents' variables are accessible even though parent doesn't have any input. 
        return GetCircleArea(radius) * height;
    }
}

LINQ ऑपरेटर्स के लिए स्थानीय फ़ंक्शंस काफी सरल होते हैं, जहाँ आपको आमतौर पर लॉजिक चेक को तर्क बनाने के लिए वास्तविक लॉजिक से अलग-अलग तर्क जांच को अलग करना पड़ता है, जब तक कि पुनरावृत्ति शुरू न हो जाए।

उदाहरण

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source, 
    Func<TSource, bool> predicate)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (predicate == null) throw new ArgumentNullException(nameof(predicate));

    return iterator();

    IEnumerable<TSource> iterator()
    {
        foreach (TSource element in source)
            if (predicate(element))
                yield return element;
    }
}

स्थानीय फ़ंक्शंस भी async और await खोजशब्दों का समर्थन करते हैं।

उदाहरण

async Task WriteEmailsAsync()
{
    var emailRegex = new Regex(@"(?i)[a-z0-9_.+-]+@[a-z0-9-]+\.[a-z0-9-.]+");
    IEnumerable<string> emails1 = await getEmailsFromFileAsync("input1.txt");
    IEnumerable<string> emails2 = await getEmailsFromFileAsync("input2.txt");
    await writeLinesToFileAsync(emails1.Concat(emails2), "output.txt");

    async Task<IEnumerable<string>> getEmailsFromFileAsync(string fileName)
    {
        string text;

        using (StreamReader reader = File.OpenText(fileName))
        {
            text = await reader.ReadToEndAsync();
        }

        return from Match emailMatch in emailRegex.Matches(text) select emailMatch.Value;
    }

    async Task writeLinesToFileAsync(IEnumerable<string> lines, string fileName)
    {
        using (StreamWriter writer = File.CreateText(fileName))
        {
            foreach (string line in lines)
            {
                await writer.WriteLineAsync(line);
            }
        }
    }
}

एक महत्वपूर्ण बात जो आपने देखी होगी वह यह है कि स्थानीय कार्यों को return स्टेटमेंट के तहत परिभाषित किया जा सकता है, उन्हें इसके ऊपर परिभाषित करने की आवश्यकता नहीं है। इसके अतिरिक्त, स्थानीय फ़ंक्शंस आमतौर पर "लोअर केमसेलसीज़" नामकरण सम्मेलन का अनुसरण करते हैं क्योंकि वर्ग के फ़ंक्शंस फ़ंक्शंस से अधिक आसानी से खुद को अलग करते हैं।

पैटर्न मिलान

C # के लिए पैटर्न मिलान एक्सटेंशन, कार्यात्मक भाषाओं से मेल खाने वाले पैटर्न के कई लाभों को सक्षम करते हैं, लेकिन एक तरह से जो अंतर्निहित भाषा की भावना के साथ आसानी से एकीकृत करते हैं

switch अभिव्यक्ति

पैटर्न मिलान प्रकारों पर स्विच करने के लिए switch स्टेटमेंट का विस्तार करता है:

class Geometry {} 

class Triangle : Geometry
{
    public int Width { get; set; }
    public int Height { get; set; }
    public int Base { get; set; }
}

class Rectangle : Geometry
{
    public int Width { get; set; }
    public int Height { get; set; }
}

class Square : Geometry
{
    public int Width { get; set; }
}

public static void PatternMatching()
{
    Geometry g = new Square { Width = 5 }; 
    
    switch (g)
    {
        case Triangle t:
            Console.WriteLine($"{t.Width} {t.Height} {t.Base}");
            break;
        case Rectangle sq when sq.Width == sq.Height:
            Console.WriteLine($"Square rectangle: {sq.Width} {sq.Height}");
            break;
        case Rectangle r:
            Console.WriteLine($"{r.Width} {r.Height}");
            break;
        case Square s:
            Console.WriteLine($"{s.Width}");
            break;
        default:
            Console.WriteLine("<other>");
            break;
    }
}

is अभिव्यक्ति

पैटर्न मिलान फैली is एक प्रकार के लिए जाँच करें और एक ही समय में एक नया वेरिएबल घोषित करने के लिए ऑपरेटर।

उदाहरण

7.0
string s = o as string;
if(s != null)
{
    // do something with s
}

के रूप में फिर से लिखा जा सकता है:

7.0
if(o is string s)
{
    //Do something with s
};

यह भी ध्यान दें कि पैटर्न वैरिएबल s का दायरा if इकोलॉजिंग स्कोप के अंत तक पहुंचने वाले ब्लॉक के बाहर तक बढ़ा दिया गया है, उदाहरण:

if(someCondition)
{
   if(o is string s)
   {
      //Do something with s
   }
   else
   {
     // s is unassigned here, but accessible 
   }

   // s is unassigned here, but accessible 
}
// s is not accessible here

वापसी और रेफरी स्थानीय

रीफ़ रिटर्न और रेफ लोकल असुरक्षित पॉइंटर्स का सहारा लिए बिना मेमोरी को कॉपी करने के बजाय मेमोरी के ब्लॉक में हेरफेर और रिटर्न के लिए उपयोगी होते हैं।

वापसी वापसी

public static ref TValue Choose<TValue>(
    Func<bool> condition, ref TValue left, ref TValue right)
{
    return condition() ? ref left : ref right;
}

इसके साथ आप कुछ शर्तों के आधार पर उनमें से एक के संदर्भ में दो मान पास कर सकते हैं:

Matrix3D left = …, right = …;
Choose(chooser, ref left, ref right).M20 = 1.0;

रेफरी स्थानीय

public static ref int Max(ref int first, ref int second, ref int third)
{
    ref int max = first > second ? ref first : ref second;
    return max > third ? ref max : ref third;
}
…
int a = 1, b = 2, c = 3;
Max(ref a, ref b, ref c) = 4;
Debug.Assert(a == 1); // true
Debug.Assert(b == 2); // true
Debug.Assert(c == 4); // true

असुरक्षित रेफरी संचालन

में System.Runtime.CompilerServices.Unsafe असुरक्षित संचालन का एक सेट परिभाषित किया गया है कि आप हेरफेर करने की अनुमति ref मूल्यों के रूप में यदि वे संकेत दिए गए थे, मूल रूप से।

उदाहरण के लिए, मेमोरी एड्रेस ( ref ) को एक अलग प्रकार के रूप में फिर से लिखना

byte[] b = new byte[4] { 0x42, 0x42, 0x42, 0x42 };

ref int r = ref Unsafe.As<byte, int>(ref b[0]);
Assert.Equal(0x42424242, r);

0x0EF00EF0;
Assert.Equal(0xFE, b[0] | b[1] | b[2] | b[3]);

से सावधान रहें endianness , जैसे जब ऐसा करने हालांकि, जाँच BitConverter.IsLittleEndian अगर जरूरत है और उसके अनुसार संभाल।

या किसी सरणी में असुरक्षित तरीके से पुनरावृति करें:

int[] a = new int[] { 0x123, 0x234, 0x345, 0x456 };

ref int r1 = ref Unsafe.Add(ref a[0], 1);
Assert.Equal(0x234, r1);

ref int r2 = ref Unsafe.Add(ref r1, 2);
Assert.Equal(0x456, r2);

ref int r3 = ref Unsafe.Add(ref r2, -3);
Assert.Equal(0x123, r3);

या समान Subtract :

string[] a = new string[] { "abc", "def", "ghi", "jkl" };

ref string r1 = ref Unsafe.Subtract(ref a[0], -2);
Assert.Equal("ghi", r1);

ref string r2 = ref Unsafe.Subtract(ref r1, -1);
Assert.Equal("jkl", r2);

ref string r3 = ref Unsafe.Subtract(ref r2, 3);
Assert.Equal("abc", r3);

इसके अतिरिक्त, यदि कोई दो ref मान समान है, तो वही जांच कर सकता है:

long[] a = new long[2];

Assert.True(Unsafe.AreSame(ref a[0], ref a[0]));
Assert.False(Unsafe.AreSame(ref a[0], ref a[1]));

लिंक

रोजलिन गितुब अंक

System.Runtime.CompilerServices.Unsafe पर जीथब

भाव फेंकना

C # 7.0 कुछ स्थानों पर एक अभिव्यक्ति के रूप में फेंकने की अनुमति देता है:

class Person
{
    public string Name { get; }

    public Person(string name) => Name = name ?? throw new ArgumentNullException(nameof(name));

    public string GetFirstName()
    {
        var parts = Name.Split(' ');
        return (parts.Length > 0) ? parts[0] : throw new InvalidOperationException("No name!");
    }

    public string GetLastName() => throw new NotImplementedException();
}

C # 7.0 से पहले, यदि आप एक अभिव्यक्ति निकाय से एक अपवाद फेंकना चाहते हैं, तो आपको निम्न करना होगा:

var spoons = "dinner,desert,soup".Split(',');

var spoonsArray = spoons.Length > 0 ? spoons : null;

if (spoonsArray == null) 
{
    throw new Exception("There are no spoons");
}

या

var spoonsArray = spoons.Length > 0 
    ? spoons 
    : new Func<string[]>(() => 
      {
          throw new Exception("There are no spoons");
      })();

C # 7.0 में उपरोक्त अब सरल हो गया है:

var spoonsArray = spoons.Length > 0 ? spoons : throw new Exception("There are no spoons");

विस्तारित अभिव्यक्ति शारीरिक सदस्यों की सूची

C # 7.0 एक्सेसर्स, कंस्ट्रक्टर और फाइनलर्स को उन चीजों की सूची में जोड़ता है जिनकी अभिव्यक्ति बॉडी हो सकती है:

class Person
{
    private static ConcurrentDictionary<int, string> names = new ConcurrentDictionary<int, string>();

    private int id = GetId();

    public Person(string name) => names.TryAdd(id, name); // constructors

    ~Person() => names.TryRemove(id, out _);              // finalizers

    public string Name
    {
        get => names[id];                                 // getters
        set => names[id] = value;                         // setters
    }
}

त्यागकर्ता ऑपरेटर के लिए बाहर की घोषणा संस्करण भी देखें।

ValueTask

Task<T> एक वर्ग है और परिणाम उपलब्ध होने पर इसके आवंटन के अनावश्यक ओवरहेड का कारण बनता है।

ValueTask<T> एक संरचना है और एक के आवंटन को रोकने के लिए शुरू किया गया है Task async आपरेशन के परिणाम के मामले में पहले से ही वस्तु का इंतजार के समय में उपलब्ध है।

तो ValueTask<T> दो लाभ प्रदान करता है:

1. प्रदर्शन में वृद्धि

यहाँ एक Task<T> उदाहरण है:

  • हीप आवंटन की आवश्यकता है
  • जेआईटी के साथ 120ns लेता है
async Task<int> TestTask(int d)
{
    await Task.Delay(d);
    return 10;
}

यहाँ एनालॉग ValueTask<T> उदाहरण दिया गया है:

  • कोई ढेर आवंटन करता है, तो परिणाम तुल्यकालिक में जाना जाता है (जो इसके बारे में क्योंकि इस मामले में नहीं है Task.Delay है, लेकिन अक्सर कई वास्तविक दुनिया में है async / await परिदृश्यों)
  • JIT के साथ 65ns लेता है
async ValueTask<int> TestValueTask(int d)
{
    await Task.Delay(d);
    return 10;
}

2. कार्यान्वयन लचीलापन में वृद्धि

तुल्यकालिक होने की इच्छा रखने वाले एक async इंटरफ़ेस के कार्यान्वयन या तो Task.Run या Task.FromResult (ऊपर चर्चा किए गए प्रदर्शन दंड के परिणामस्वरूप) का उपयोग करने के लिए मजबूर किया जाएगा। इस प्रकार तुल्यकालिक कार्यान्वयन के खिलाफ कुछ दबाव है।

लेकिन ValueTask<T> , कार्यान्वयन कॉलर्स को प्रभावित किए बिना तुल्यकालिक या अतुल्यकालिक होने के बीच चयन करने के लिए अधिक स्वतंत्र हैं।

उदाहरण के लिए, यहां अतुल्यकालिक विधि के साथ एक इंटरफ़ेस है:

interface IFoo<T>
{
    ValueTask<T> BarAsync();
}

... और यहां बताया गया है कि यह तरीका कैसे हो सकता है:

IFoo<T> thing = getThing();
var x = await thing.BarAsync();

ValueTask साथ, उपरोक्त कोड या तो तुल्यकालिक या अतुल्यकालिक कार्यान्वयन के साथ काम करेगा:

समकालिक कार्यान्वयन:

class SynchronousFoo<T> : IFoo<T>
{
    public ValueTask<T> BarAsync()
    {
        var value = default(T);
        return new ValueTask<T>(value);
    }
}

अतुल्यकालिक कार्यान्वयन

class AsynchronousFoo<T> : IFoo<T>
{
    public async ValueTask<T> BarAsync()
    {
        var value = default(T);
        await Task.Delay(1);
        return value;
    }
}

टिप्पणियाँ

हालाँकि ValueTask संरचना को C # 7.0 में जोड़ने की योजना बनाई जा रही थी, लेकिन इसे फिलहाल एक अन्य पुस्तकालय के रूप में रखा गया है। ValueTask <T> System.Threading.Tasks.Extensions पैकेज नुगेट गैलरी से डाउनलोड किया जा सकता है



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow