System.ValueTuple এবং System.Tuple এর মধ্যে পার্থক্য কী?


139

আমি কয়েকটি সি # 7 লাইব্রেরিটি ValueTupleবিচ্ছেদ করেছি এবং দেখেছি জেনেরিকগুলি ব্যবহার করা হচ্ছে। কি ValueTuplesএবং কেন Tupleপরিবর্তে না ?


আমি মনে করি এটি ডট নেট টিপল ক্লাসের উল্লেখ করে। আপনি দয়া করে একটি নমুনা কোড ভাগ করতে পারেন। যাতে এটি বুঝতে সহজ হবে।
রণদীপ দত্ত

14
@ রণাদিপ দত্ত: টিপল কী তা আপনি যদি জানেন তবে প্রশ্নটি বোঝার জন্য আপনার স্যাম্পল কোডের দরকার নেই। প্রশ্নটি নিজেই সোজা: ভ্যালুটুপল কী এবং এটি টুপলের থেকে কীভাবে আলাদা?
বোল্টক্লক

1
@ বল্টক্লক: এই কারণেই আমি সেই প্রসঙ্গে কোনও উত্তর দিইনি। আমি সি # তে জানি, এখানে একটি টুপল শ্রেণি রয়েছে যা আমি প্রায়শই প্রায়শই ব্যবহার করি এবং একই ক্লাসটিকে আমি পাওয়ারশেলের মাধ্যমেও কল করি। এটি একটি রেফারেন্স টাইপ। এখন অন্যান্য উত্তরগুলি দেখে আমি বুঝতে পেরেছিলাম যে এখানে একটি মান ধরণের রয়েছে যা ভালুয়েটুপল নামে পরিচিত। যদি কোনও নমুনা থাকে তবে আমি তার ব্যবহারটি জানতে চাই।
রণদীপ দত্ত

2
রোজলিনের সোর্স কোডটি গিথুবে পাওয়া গেলে আপনি এগুলি কেন পাকা করবেন?
জেইন মক্কি

@ ইউজার 3185569 সম্ভবত এফ 12 জিনিসগুলি ডিসপম্পাইল করে এবং গিটহাবে ঝাঁপিয়ে
পড়ার

উত্তর:


203

কি ValueTuplesএবং কেন Tupleপরিবর্তে না ?

ValueTupleহ'ল একটি কাঠামো যা মূল System.Tupleশ্রেণীর মতো একটি টুপল প্রতিবিম্বিত করে ।

মধ্যে মূল পার্থক্য Tupleএবং ValueTupleআছেন:

  • System.ValueTupleএকটি মান প্রকার (স্ট্রাক্ট), অন্যদিকে System.Tupleএকটি রেফারেন্স টাইপ ( class)। বরাদ্দ এবং জিসি চাপ সম্পর্কে কথা বলার সময় এটি অর্থবহ।
  • System.ValueTupleএটি কেবল একটি নয় struct, এটি একটি পরিবর্তনীয় , এবং এগুলি ব্যবহার করার সময় একজনকে সতর্কতা অবলম্বন করা উচিত। System.ValueTupleক্ষেত্র হিসাবে যখন কোনও শ্রেণি একটি ক্ষেত্র ধারণ করে তখন কী ঘটে তা ভাবুন ।
  • System.ValueTuple বৈশিষ্ট্যের পরিবর্তে ক্ষেত্রগুলির মাধ্যমে এর আইটেমগুলি প্রকাশ করে।

সি # 7 অবধি, টিপলগুলি ব্যবহার করা খুব সুবিধাজনক ছিল না। তাদের ক্ষেত্র নাম Item1, Item2সবচেয়ে অন্যান্য ভাষায় মত তাদের জন্য ইত্যাদি, এবং ভাষা সরবরাহকৃত নি সিনট্যাক্স চিনি না (পাইথন, Scala)।

.NET ভাষা নকশা দল যখন ভাষা স্তরে টিপলগুলি সংযুক্ত করার এবং সিনট্যাক্স চিনির সাথে তাদের যুক্ত করার সিদ্ধান্ত নিয়েছিল তখন একটি গুরুত্বপূর্ণ বিষয় ছিল পারফরম্যান্স। ValueTupleমান ধরণের হওয়ার সাথে সাথে আপনি তাদের ব্যবহারের সময় জিসি চাপ এড়াতে পারবেন কারণ (বাস্তবায়নের বিশদ হিসাবে) এগুলি স্ট্যাকের জন্য বরাদ্দ দেওয়া হবে।

অতিরিক্তভাবে, structরানটাইম দ্বারা একটি স্বয়ংক্রিয় (অগভীর) সমতা শব্দার্থক পদার্থ পায়, যেখানে এটি classহয় না। যদিও ডিজাইন দলটি নিশ্চিত করেছে যে টিউপলসের জন্য আরও বেশি অনুকূলিত সাম্যতা থাকবে, তাই এটির জন্য একটি কাস্টম সমতা কার্যকর করা হয়েছে।

এর নকশা নোটগুলিরTuples একটি অনুচ্ছেদ এখানে দেওয়া হয়েছে :

কাঠামো বা শ্রেণি:

যেমনটি উল্লেখ করা হয়েছে, আমি structsতার চেয়ে দ্বিগুণ প্রকার তৈরির প্রস্তাব করছি classes, যাতে কোনও বরাদ্দ জরিমানা তাদের সাথে যুক্ত না হয়। এগুলি যথাসম্ভব হালকা হওয়া উচিত।

যুক্তিযুক্তভাবে, structsআরও ব্যয়বহুল হয়ে উঠতে পারে, কারণ অ্যাসাইনমেন্টটি একটি বড় মানের অনুলিপি করে। সুতরাং যদি তাদের তৈরি হওয়ার চেয়ে অনেক বেশি নির্ধারিত করা হয় structsতবে এটি একটি খারাপ পছন্দ হবে।

তাদের খুব অনুপ্রেরণায়, যদিও, টিপলগুলি সংক্ষিপ্ত হয়। অংশগুলি সম্পূর্ণর চেয়ে বেশি গুরুত্বপূর্ণ হলে আপনি সেগুলি ব্যবহার করবেন। সুতরাং সাধারণ প্যাটার্নটি হ'ল এটি নির্মাণ, ফিরে আসা এবং তত্ক্ষণাত তাদের ডেকনস্ট্রাক্ট করা। এই পরিস্থিতিতে স্ট্রাক্টগুলি পরিষ্কারভাবে পছন্দসই।

স্ট্রাক্টের আরও অনেকগুলি সুবিধা রয়েছে যা নিম্নলিখিতগুলির মধ্যে সুস্পষ্ট হয়ে উঠবে।

উদাহরণ:

আপনি সহজেই দেখতে পাবেন যে সাথে কাজ করা System.Tupleখুব দ্রুতই অস্পষ্ট হয়ে যায়। উদাহরণস্বরূপ, বলুন আমাদের একটি পদ্ধতি রয়েছে যা একটি যোগফল এবং একটি এর গণনা গণনা করে List<Int>:

public Tuple<int, int> DoStuff(IEnumerable<int> values)
{
    var sum = 0;
    var count = 0;

    foreach (var value in values) { sum += value; count++; }

    return new Tuple(sum, count);
}

প্রাপ্তির শেষে, আমরা এর সাথে শেষ করি:

Tuple<int, int> result = DoStuff(Enumerable.Range(0, 10));

// What is Item1 and what is Item2?
// Which one is the sum and which is the count?
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);

আপনি যেভাবে নাম যুক্তিগুলিতে মান টিউপলগুলি ডিকনস্ট্রাক্ট করতে পারেন তা হ'ল বৈশিষ্ট্যের আসল শক্তি:

public (int sum, int count) DoStuff(IEnumerable<int> values) 
{
    var res = (sum: 0, count: 0);
    foreach (var value in values) { res.sum += value; res.count++; }
    return res;
}

এবং গ্রহণের শেষে:

var result = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {result.Sum}, Count: {result.Count}");

বা:

var (sum, count) = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {sum}, Count: {count}");

সংকলক গুডিজ:

যদি আমরা আমাদের পূর্ববর্তী উদাহরণের আড়ালে নজর রাখি, আমরা ValueTupleযখন কম্পাইলারটিকে ডিকনস্ট্রাক্ট করতে বলি তখন আমরা ঠিক দেখতে পাই যে সংকলকটি কীভাবে ব্যাখ্যা করছে :

[return: TupleElementNames(new string[] {
    "sum",
    "count"
})]
public ValueTuple<int, int> DoStuff(IEnumerable<int> values)
{
    ValueTuple<int, int> result;
    result..ctor(0, 0);
    foreach (int current in values)
    {
        result.Item1 += current;
        result.Item2++;
    }
    return result;
}

public void Foo()
{
    ValueTuple<int, int> expr_0E = this.DoStuff(Enumerable.Range(0, 10));
    int item = expr_0E.Item1;
    int arg_1A_0 = expr_0E.Item2;
}

অভ্যন্তরীণভাবে, সংকলিত কোডটি ব্যবহার করে Item1এবং Item2, তবে আমরা একটি পচে যাওয়া টিউপল নিয়ে কাজ করার কারণে এগুলি সমস্ত আমাদের থেকে দূরে সরে যায়। নামযুক্ত আর্গুমেন্টের সাথে একটি টিপল এর সাথে টীকা দেওয়া হয় TupleElementNamesAttribute। আমরা যদি পঁচন পরিবর্তনের পরিবর্তে একটি একক তাজা পরিবর্তনশীল ব্যবহার করি তবে আমরা পাই:

public void Foo()
{
    ValueTuple<int, int> valueTuple = this.DoStuff(Enumerable.Range(0, 10));
    Console.WriteLine(string.Format("Sum: {0}, Count: {1})", valueTuple.Item1, valueTuple.Item2));
}

নোট কম্পাইলার এখনও কিছু জাদু ঘটতে (অনুষঙ্গ এর মাধ্যমে) যখন আমরা আমাদের অ্যাপ্লিকেশন ডিবাগ, যেমন এটি দেখতে অদ্ভুত হবে করতে আছে Item1, Item2


1
মনে রাখবেন যে আপনি আরও সহজ (এবং আমার মতে পছন্দনীয়) বাক্য var (sum, count) = DoStuff(Enumerable.Range(0, 10));
গঠনটিও

@ অ্যাবিয়ন 47 উভয় ধরণের পার্থক্য থাকলে কী হবে?
ইউভাল ইতজকভ

এছাড়াও আপনার পয়েন্টগুলি "এটি একটি পরিবর্তনীয় কাঠামো" এবং "এটি কেবল পাঠযোগ্য ক্ষেত্রগুলি প্রকাশ করে" তাতে সম্মত হয় কীভাবে?
কোডসইনচাউস

পছন্দ করেছেন আমি [এটি] ( github.com/dotnet/corefx/blob/master/src/Common/src/System/… ) দেখেছি , তবে আমি মনে করি না যে এটি কম্পাইলার দ্বারা নির্গত হয়, যেহেতু স্থানীয় ক্ষেত্রগুলি হতে পারে না যেভাবেই পঠনযোগ্য। আমি মনে করি প্রস্তাবটির অর্থ "আপনি যদি চান তবে এগুলিকে কেবল পঠন করতে পারেন তবে এটি আপনার উপর নির্ভর করে" , যা আমি ভুল ব্যাখ্যা দিয়েছিলাম।
ইউভাল ইতজকভ

1
কিছু নিট: "এগুলি স্ট্যাকের জন্য বরাদ্দ দেওয়া হবে" - কেবল স্থানীয় ভেরিয়েবলের ক্ষেত্রে এটি সত্য। কোনও সন্দেহ নেই যে আপনি এটি জানেন তবে দুর্ভাগ্যক্রমে আপনি যেভাবে এই শব্দটি উচ্চারণ করেছেন তা সম্ভবত এই ধরণের রূপকথাকে ধরে রাখতে পারে যে মান ধরণের সবসময় স্ট্যাকের মধ্যে থাকে।
পিটার ডুনিহো

26

মধ্যে পার্থক্য Tupleএবং ValueTupleযে Tupleএকটি রেফারেন্স টাইপ করতে হবে এবং ValueTupleএকটি মান প্রকার। দ্বিতীয়টি পছন্দসই কারণ সি # 7 এর ভাষার পরিবর্তনের ক্ষেত্রে টিপলগুলি প্রায়শই ঘন ঘন ব্যবহৃত হয় তবে প্রতিটি টিপলের জন্য স্তূপে একটি নতুন অবজেক্ট বরাদ্দ করা একটি পারফরম্যান্স উদ্বেগ, বিশেষত যখন এটি অপ্রয়োজনীয়।

যাইহোক, সি # 7, যা এই ধারণার আপনি কখনই যে আছে স্পষ্টভাবে সিনট্যাক্স চিনি tuple ব্যবহারের জন্য যোগ করা হচ্ছে, কারণ এই দুই ধরনের যেকোন ব্যবহার করতে। উদাহরণস্বরূপ, সি # 6 এ, আপনি যদি কোনও মান ফেরত দেওয়ার জন্য একটি টুপল ব্যবহার করতে চান, আপনাকে নিম্নলিখিতগুলি করতে হবে:

public Tuple<string, int> GetValues()
{
    // ...
    return new Tuple(stringVal, intVal);
}

var value = GetValues();
string s = value.Item1; 

তবে, সি # 7 এ আপনি এটি ব্যবহার করতে পারেন:

public (string, int) GetValues()
{
    // ...
    return (stringVal, intVal);
}

var value = GetValues();
string s = value.Item1; 

আপনি আরও একধাপ এগিয়ে যেতে পারেন এবং মানগুলির নাম দিতে পারেন:

public (string S, int I) GetValues()
{
    // ...
    return (stringVal, intVal);
}

var value = GetValues();
string s = value.S; 

... অথবা পুরোপুরি টিপলটি ডিকনস্ট্রাক্ট করুন:

public (string S, int I) GetValues()
{
    // ...
    return (stringVal, intVal);
}

var (S, I) = GetValues();
string s = S;

টিপলগুলি প্রায়শই সি # প্রাক -7 এ ব্যবহৃত হত না কারণ এগুলি জটিল এবং ভার্বোজ ছিল এবং কেবলমাত্র এমন ক্ষেত্রে ব্যবহৃত হয় যেখানে কাজের জন্য কেবলমাত্র একক উদাহরণের জন্য ডেটা শ্রেণি / কাঠামো তৈরি করা তার পক্ষে মূল্যমানের চেয়ে বেশি ঝামেলা হতে পারে। তবে সি # 7 এ, টিপলগুলির এখন ভাষা-স্তরের সমর্থন রয়েছে, সুতরাং এগুলি ব্যবহার করা অনেক বেশি পরিষ্কার এবং আরও কার্যকর।


10

আমি উভয় জন্য উৎস দিকে তাকিয়ে Tupleএবং ValueTuple। পার্থক্য হল Tupleএকটি হল classএবং ValueTupleএকটি হল structযে কার্যকরী IEquatable

এটার মানে হল যে Tuple == Tupleফিরে আসবে falseযদি তারা একই উদাহরণস্বরূপ হয় না, কিন্তু ValueTuple == ValueTupleফিরে আসবে trueযদি তারা একই ধরনের এবং হয় Equalsআয় trueমান সেগুলির মধ্যে উপস্থিত প্রত্যেকের জন্য।


এটি যদিও এর চেয়ে বেশি।
বোল্টক্লক

2
@ বল্টক্লক আপনার মন্তব্যটি গঠনমূলক হবে যদি আপনি বিস্তারিতভাবে বর্ণনা করেন
পিটার মরিস

3
এছাড়াও, মান ধরণের অগত্যা স্ট্যাকের উপর না যায়। পার্থক্যটি হ'ল শব্দার্থকভাবে রেফারেন্সের পরিবর্তে মানটি উপস্থাপন করে, যখনই সেই পরিবর্তনশীলটি সঞ্চিত থাকে, যা স্ট্যাক বা নাও থাকতে পারে।
পরিবেশন করুন

6

অন্যান্য উত্তরগুলি গুরুত্বপূর্ণ পয়েন্টগুলি উল্লেখ করতে ভুলে গেছে rep পুনরায় ব্যবহারের পরে, আমি উত্স কোড থেকে এক্সএমএল ডকুমেন্টেশনটি উল্লেখ করতে চাই :

মান 0 থেকে 8 টির মধ্যে রানটাইম বাস্তবায়ন যা সি # তে টিপলস এবং এফ # তে স্ট্রাক্ট টিপলসকে অন্তর্ভুক্ত করে।

ভাষার সিনট্যাক্সের মাধ্যমে তৈরি বাদে এগুলি ValueTuple.Createকারখানার পদ্ধতিগুলির মাধ্যমে খুব সহজেই তৈরি করা হয় । System.ValueTupleধরনের থেকে পৃথক System.Tupleযে প্রকারসমূহ:

  • তারা ক্লাসের চেয়ে স্ট্রাক্ট,
  • এগুলি কেবল পঠনযোগ্য নয় , পরিবর্তিত
  • তাদের সদস্য (যেমন আইটেম 1, আইটেম 2, ইত্যাদি) বৈশিষ্ট্যের পরিবর্তে ক্ষেত্র।

এই ধরণের এবং সি # 7.0 সংকলক প্রবর্তনের সাথে আপনি সহজেই লিখতে পারেন

(int, string) idAndName = (1, "John");

এবং একটি পদ্ধতি থেকে দুটি মান ফেরত দিন:

private (int, string) GetIdAndName()
{
   //.....
   return (id, name);
}

এর বিপরীতে আপনি System.Tupleএর সদস্যদের আপডেট করতে পারবেন (পরিবর্তনযোগ্য) কারণ তারা সর্বজনীন পঠন-লিখনের ক্ষেত্র যা অর্থপূর্ণ নাম দেওয়া যেতে পারে:

(int id, string name) idAndName = (1, "John");
idAndName.name = "New Name";

"আরিটি 0 থেকে 8"। আহ, আমি এগুলি পছন্দ করি যে তারা 0 টি টিপল অন্তর্ভুক্ত করে। এটি এক ধরণের খালি প্রকার হিসাবে ব্যবহৃত হতে পারে এবং জেনেরিকগুলিতে অনুমোদিত হবে যখন কোনও ধরণের প্যারামিটারের প্রয়োজন হয় না, class MyNonGenericType : MyGenericType<string, ValueTuple, int>ইত্যাদি ইত্যাদি
জেপ্প স্টিগ নীলসেন

6

উপরের মতামত ছাড়াও, ভ্যালুটিপল এর একটি দুর্ভাগ্যজনক গোটাচা হ'ল, মানের ধরণ হিসাবে, আইএল-এ সংকলিত হয়ে নাম যুক্তিগুলি মুছে ফেলা হয়, সুতরাং রানটাইমগুলিতে সেগুলি সিরিয়ালাইজেশনের জন্য উপলব্ধ নয়।

যেমন আপনার মিষ্টি নামের যুক্তিগুলি এখনও আইসন.এনইটি-র মাধ্যমে ক্রমিকায়িত করার পরে "আইটেম 1", "আইটেম 2" ইত্যাদি হিসাবে শেষ হবে।


2
সুতরাং প্রযুক্তিগতভাবে এটি একটি মিল এবং কোনও পার্থক্য নয়;)
জেএড

2

এই দুটি ফ্যাক্টয়েডগুলির বিষয়ে একটি দ্রুত ব্যাখ্যা যোগ করতে দেরীতে যোগদান:

  • তারা ক্লাসের চেয়ে স্ট্রাক্ট
  • তারা কেবল পঠনযোগ্য নয় পরিবর্তিত হয়

কেউ ভাবেন যে মান-টিপলস-এ-ম্যাসে পরিবর্তন করা সোজা হবে:

 foreach (var x in listOfValueTuples) { x.Foo = 103; } // wont even compile because x is a value (struct) not a variable

 var d = listOfValueTuples[0].Foo;

কেউ এ জাতীয়ভাবে চেষ্টা করার চেষ্টা করতে পারে:

 // initially *.Foo = 10 for all items
 listOfValueTuples.Select(x => x.Foo = 103);

 var d = listOfValueTuples[0].Foo; // 'd' should be 103 right? wrong! it is '10'

এই উদ্বিগ্ন আচরণের কারণ হ'ল মান-টিপলস হুবহু মান-ভিত্তিক (স্ট্রাক্ট) এবং সুতরাং .সलेक्ट (...) কলটি মূলগুলির পরিবর্তে ক্লোনড-স্ট্রাক্টগুলিতে কাজ করে। এটি সমাধান করার জন্য আমাদের অবশ্যই অবলম্বন করতে হবে:

 // initially *.Foo = 10 for all items
 listOfValueTuples = listOfValueTuples
     .Select(x => {
         x.Foo = 103;
         return x;
     })
     .ToList();

 var d = listOfValueTuples[0].Foo; // 'd' is now 103 indeed

বিকল্পভাবে অবশ্যই একটি সহজ পদ্ধতির চেষ্টা করতে পারে:

   for (var i = 0; i < listOfValueTuples.Length; i++) {
        listOfValueTuples[i].Foo = 103; //this works just fine

        // another alternative approach:
        //
        // var x = listOfValueTuples[i];
        // x.Foo = 103;
        // listOfValueTuples[i] = x; //<-- vital for this alternative approach to work   if you omit this changes wont be saved to the original list
   }

   var d = listOfValueTuples[0].Foo; // 'd' is now 103 indeed

আশা করি এটি কাউকে তালিকা-হোস্ট করা মান-টিপলগুলি থেকে লেজের মাথা তৈরি করতে লড়াই করতে সহায়তা করবে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.