C# 7.1 - Tuple Name Inference
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: چهار دقیقه

در مطلب «C# 7 - Tuple return types and deconstruction» با نوع‌های جدید بازگشتی Tuple در C# 7.0 آشنا شدیم. در C# 7.1 تشخیص نام اعضای Tuple تعریف شده بهبود یافته و از این لحاظ شبیه به anonymous types شده‌است. مفهوم «Name Inference» یا «حدس زدن نام‌ها» را با یک مثال بهتر می‌توان توضیح داد.
string name = "User 1";
int age = 20;
var personTuple = (name, age);
Console.WriteLine(personTuple.Item1); // User 1
Console.WriteLine(personTuple.Item2); // 20
در C# 7.0 مفهوم «Name Inference» پیاده سازی نشده‌است. به همین جهت کامپایلر قادر نیست نام اعضای Tuple تعریف شده‌ی فوق را حدس بزند و برای دسترسی به آن‌ها باید تنها از Item1 و Item2 مانند قبل استفاده کرد. البته اگر برای اعضای Tuple نام تعریف کنیم (قسمت «مفهوم Tuple Literals»)، آنگاه می‌توان Item1 و Item2 را با نام‌های این اعضاء جایگزین کرد:
string name = "User 1";
int age = 20;
var personTuple = (name: name, age:age);
Console.WriteLine(personTuple.name); // User 1
Console.WriteLine(personTuple.age); // 20
بنابراین ذکر نام صریح اعضای Tuple در سی‌شارپ 7 الزامی است؛ در غیراینصورت باید با همان نام‌های عمومی Item1 و Item2 جهت دسترسی به این اعضاء، کار کرد.
این وضعیت در C# 7.1 بهبود یافته‌است و اکنون کامپایلر در صورت عدم ذکر صریح نام اعضای Tuple، قادر است این نام‌ها را دقیقا بر اساس نام متغیرها، همانند قابلیتی که در مورد anonymous types وجود دارد، تعیین کند و حدس بزند:
string name = "User 1";
int age = 20;
var personTuple = (name, age);
Console.WriteLine(personTuple.name); // User 1
Console.WriteLine(personTuple.age); // 20
این مثال، شبیه به اولین مثالی است که در مورد C# 7.0 ذکر شد. اما در C# 7.1 نیازی به ذکر Item1 و Item2 جهت دسترسی به اعضای Tuple تعریف شده نیست (هرچند هنوز هم مجاز است) و کامپایلر نام این اعضاء را از نام متغیرهای متناظر با آن‌ها حدس می‌زند.


مثال‌هایی از حدس زدن نام‌های اعضای Tuple در C# 7.1

مثال اول همان حدس زدن نام‌های اعضای Tuple بر اساس نام متغیرهای محلی متناظر با آن‌ها است.

مثال دوم بر اساس نام خواص یک شیء است که توسط یک نوع Tuple بازگشت داده می‌شود:
var p = new Person
{
   Name = "User 1",
   Age = 20
};
var personTuple = (p.Name, p.Age);
Console.WriteLine(personTuple.Name);
Console.WriteLine(personTuple.Age);

در اینجا عملگر .? نیز پشتیبانی می‌شود:
Person p = null;
var personTuple = (p?.Name, p?.Age);
Console.WriteLine(personTuple.Name); // null
Console.WriteLine(personTuple.Age); // null

مثال سوم همان مثال دوم است که در یک عبارت LINQ بکار رفته‌است:
var people = new List<Person>
{
   new Person {Name = "User 1", Age = 42},
   new Person {Name = "User 2", Age = 18},
   new Person {Name = "User 3", Age = 21}
};

var tuples = people
   .Select(person =>
           (
              person.Name,
              person.Age,
              NameAndAge: $"{person.Name} is {person.Age}"
           )
);
var name = tuples.First().Name;
var age = tuples.First().Age; 
var nameAndAge = tuples.First().NameAndAge;
در اینجا نوع خروجی عبارت LINQ نوشته شده، لیستی از Tupleها است. در Tuple خروجی آن، نام دو عضو اول، از نام خواص متناظر با آن‌ها حدس زده می‌شود. نام عنصر سوم به صورت صریح مشخص شده‌است.


نکته 1: حدس زدن نام‌ها در مورد مقادیر خروجی متدها رخ نمی‌دهد.

در مثال ذیل نمی‌توان به personTuple.FirstName بر اساس نام متد ذکر شده دسترسی یافت و تنها می‌توان از Item1 در مورد آن استفاده کرد؛ اما در مورد متغیر محلی age می‌توان:
int age = 42;
var personTuple = (FirstName(), age);
Console.WriteLine(personTuple.Item1);
Console.WriteLine(personTuple.age);


نکته 2: اگر نام اعضای Tuple یکی باشند، عملیات حدس زدن نام‌ها رخ نمی‌دهد.

var p1 = new Person
{
   Name = "User 1",
   Age = 20
};

var p2 = new Person
{
   Name = "User 2",
   Age = 22
};

var personTuple = (p1.Name, p2.Name);
Console.WriteLine(personTuple.Item1); // User 1
Console.WriteLine(personTuple.Item2); // User 2
در این مثال چون Tuple تشکیل شده دارای نام‌های یکسان Name است، امکان حدس زدن نام‌ها میسر نیست و در اینجا نیز باید از طریق Item1 و ... به اعضای Tuple دسترسی یافت (و یا می‌توان به هر عضو Tuple یک نام منحصربفرد را انتساب داد).
  • #
    ‫۶ سال و ۴ ماه قبل، سه‌شنبه ۱۱ اردیبهشت ۱۳۹۷، ساعت ۰۳:۲۳
    یکی از ویژگی‌های جالب Tuple اینه که میشه در بدنه For نوع داده‌ی متفاوتی قرار داد
    public static  void Main() 
    {
            var li = Enumerable.Range(1, 10).ToList();
            var sb = new StringBuilder();
            //for (int i=0,j=1;;) 
    //در اینجا میشه نوع‌های متفاوتی تعریف کرد
            for ( (int i, bool first) = (0, true); i < li.Count; i++, first = false)
            {
                if (!first)
                    sb.Append(", ");
                
                sb.Append(li[i]);
            }
            
            Console.WriteLine(sb.ToString());
    }
  • #
    ‫۶ سال و ۲ ماه قبل، شنبه ۲۳ تیر ۱۳۹۷، ساعت ۰۴:۱۷
    استفاده از tuple برای انجام مبادله  متغیرها
     public void Swap()
     {
          int x = 5;
          int y = 50;
          (x, y) = (y, x);
     }