۱۳۸۹/۰۲/۱۷

Tuple در دات نت 4


نوع جديدي در دات نت 4 به نام Tuple اضافه شده است كه در اين مطلب به بررسي آن خواهيم پرداخت.
در رياضيات، Tuple به معناي ليست مرتبي از اعضاء با تعداد مشخص است. Tuple در زبان‌هاي برنامه نويسي Dynamic مانند اف شارپ، Perl ، LISP و بسياري موارد ديگر مطلب جديدي نيست. در زبان‌هاي dynamic برنامه نويس‌ها مي‌توانند متغيرها را بدون معرفي نوع آن‌ها تعريف كنند. اما در زبان‌هاي Static مانند سي شارپ، برنامه نويس‌ها موظفند نوع متغيرها را پيش از كامپايل آن‌ها معرفي كنند كه هر چند كار كد نويسي را اندكي بيشتر مي‌كند اما به اين صورت شاهد خطاهاي كمتري نيز خواهيم بود (البته سي شارپ 4 اين مورد را با معرفي واژه‌ي كليدي dynamic تغيير داده است).
براي مثال در اف شارپ داريم:
let data = (“John Doe”, 42)

كه سبب ايجاد يك tuple كه المان اول آن يك رشته و المان دوم آن يك عدد صحيح است مي‌شود. اگر data را بخواهيم نمايش دهيم خروجي آن به صورت زير خواهد بود:
printf “%A” data
// Output: (“John Doe”,42)

در دات نت 4 فضاي نام جديدي به نام System.Tuple معرفي شده است كه در حقيقت ارائه دهنده‌ي نوعي جنريك مي‌باشد كه توانايي در برگيري انواع مختلفي را دارا است :
public class Tuple<T1>
up to:
public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>

همانند آرايه‌ها، اندازه‌ي Tuples نيز پس از تعريف قابل تغيير نيستند (immutable). اما تفاوت مهم آن با يك آرايه در اين است كه اعضاي آن مي‌توانند نوع‌هاي كاملا متفاوتي داشته باشند. همچنين تفاوت مهم آن با يك ArrayList يا آرايه‌اي از نوع Object، مشخص بودن نوع هر يك از اعضاء آن است كه type safety بيشتري را به همراه خواهد داشت و كامپايلر مي‌تواند در حين كامپايل دقيقا مشخص نمايد كه اطلاعات دريافتي از نوع صحيحي هستند يا خير.

يك مثال كامل از Tuples را در كلاس زير ملاحظه خواهيد نمود:

using System;
using System.Linq;
using System.Collections.Generic;

namespace TupleTest
{
class TupleCS4
{
#region Methods (4)

// Public Methods (4)

public static Tuple<string, string> GetFNameLName(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new NullReferenceException("name is empty.");

var nameParts = name.Split(',');

if (nameParts.Length != 2)
throw new FormatException("name must contain ','");

return Tuple.Create(nameParts[0], nameParts[1]);
}

public static void PrintSelectedTuple()
{
var list = new List<Tuple<string, int>>
{
new Tuple<string, int>("A", 1),
new Tuple<string, int>("B", 2),
new Tuple<string, int>("C", 3)
};

var item = list.Where(x => x.Item2 == 2).SingleOrDefault();
if (item != null)
Console.WriteLine("Selected Item1: {0}, Item2: {1}",
item.Item1, item.Item2);
}

public static void PrintTuples()
{
var tuple1 = new Tuple<int>(12);
Console.WriteLine("tuple1 contains: item1:{0}", tuple1.Item1);

var tuple2 = Tuple.Create("Item1", 12);
Console.WriteLine("tuple2 contains: item1:{0}, item2:{1}",
tuple2.Item1, tuple2.Item2);

var tuple3 = Tuple.Create(new DateTime(2010, 5, 6), "Item2", 20);
Console.WriteLine("tuple3 contains: item1:{0}, item2:{1}, item3:{2}",
tuple3.Item1, tuple3.Item2, tuple3.Item3);
}

public static void Tuple8()
{
var tup =
new Tuple<int, int, int, int, int, int, int, Tuple<int, int>>
(1, 2, 3, 4, 5, 6, 7, new Tuple<int, int>(8, 9));

Console.WriteLine("tup.Rest Item1: {0}, Item2: {1}",
tup.Rest.Item1,tup.Rest.Item2);
}

#endregion Methods
}
}

using System;

namespace TupleTest
{
class Program
{
static void Main()
{
var data = TupleCS4.GetFNameLName("Vahid, Nasiri");
Console.WriteLine("Data Item1:{0} & Item2:{1}",
data.Item1, data.Item2);

TupleCS4.PrintTuples();

TupleCS4.PrintSelectedTuple();

TupleCS4.Tuple8();

Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}

توضيحات :
- روش‌هاي متفاوت ايجاد Tuples را در متد PrintTuples مي‌توانيد ملاحظه نمائيد. همچنين نحوه‌ي دسترسي به مقادير هر كدام از اعضاء نيز مشخص شده است.
- كاربرد مهم Tuples در متد GetFNameLName نمايش داده شده است؛ زمانيكه نياز است تا چندين خروجي از يك تابع داشته باشيم. به اين صورت ديگر نيازي به تعريف آرگومان‌هايي به همراه واژه كليدي out نخواهد بود يا ديگر نيازي نيست تا يك شيء جديد را ايجاد كرده و خروجي را به آن نسبت دهيم. به همان سادگي زبان‌هاي dynamic در اينجا نيز مي‌توان يك tuple را ايجاد و استفاده كرد.
- بديهي است از Tuples در يك ليست جنريك و يا حالات ديگر نيز مي‌توان استفاده كرد. مثالي از اين دست را در متد PrintSelectedTuple ملاحظه خواهيد نمود. ابتدا يك ليست جنريك از Tuple ايي با دو عضو تشكيل شده است. سپس با استفاده از امكانات LINQ ، عضوي كه آيتم دوم آن مساوي 2 است يافت شده و سپس المان‌هاي آن نمايش داده مي‌شود.
- نكته‌ي ديگري را كه حين كار با Tuples مي‌توان در نظر داشت اين است كه اعضاي آن حداكثر شامل 8 عضو مي‌توانند باشند كه عضو آخر بايد يك Tuple تعريف گردد و بديهي است اين Tuple‌ نيز مي‌تواند شامل 8 عضو ديگر باشد و الي آخر كه نمونه‌اي از آن را در متد Tuple8 مي‌توان مشاهده كرد.