নেটগুলিতে স্ট্রিংগুলি কীভাবে পাস হবে?


121

আমি যখন stringকোনও ফাংশনে একটি পাস করি , তখন স্ট্রিংয়ের বিষয়বস্তুগুলির একটি পয়েন্টার কি পাস হয়, বা পুরো স্ট্রিংটি স্ট্যাকের মতো ফাংশনে পাস structহবে কি?

উত্তর:


278

একটি রেফারেন্স পাস হয়েছে; তবে, এটি প্রযুক্তিগতভাবে রেফারেন্স দ্বারা পাস করা হয়নি। এটি একটি সূক্ষ্ম, তবে খুব গুরুত্বপূর্ণ পার্থক্য। নিম্নলিখিত কোড বিবেচনা করুন:

void DoSomething(string strLocal)
{
    strLocal = "local";
}
void Main()
{
    string strMain = "main";
    DoSomething(strMain);
    Console.WriteLine(strMain); // What gets printed?
}

এখানে কী ঘটে তা বোঝার জন্য আপনার তিনটি জিনিস জানতে হবে:

  1. স্ট্রিংগুলি সি # তে রেফারেন্সের ধরণ।
  2. এগুলিও অপরিবর্তনীয়, সুতরাং যে কোনও সময় আপনি এমন কিছু করেন যা দেখে মনে হয় আপনি স্ট্রিং পরিবর্তন করছেন, আপনি নন। সম্পূর্ণ নতুন স্ট্রিং তৈরি হয়ে যায়, রেফারেন্সটি এটিকে নির্দেশ করে এবং পুরানোটি ফেলে দেওয়া হয়।
  3. স্ট্রিংগুলি রেফারেন্সের ধরণের হলেও রেফারেন্স strMainদ্বারা পাস করা হয় না। এটি একটি রেফারেন্স টাইপ, তবে রেফারেন্সটি নিজেই মান দ্বারা পাস হয় । আপনি যে কোনও সময় refকীওয়ার্ড ছাড়াই প্যারামিটারটি পাস করেন ( outপ্যারামিটার গণনা করছে না ), আপনি মান দিয়ে কিছু পাস করেছেন।

সুতরাং এর অর্থ অবশ্যই আপনি ... মান অনুসারে একটি রেফারেন্স পাস করছেন। এটি যেহেতু একটি রেফারেন্স টাইপ, কেবলমাত্র রেফারেন্সটি স্ট্যাকের অনুলিপি করা হয়েছিল। তবে তার মানে কী?

মান অনুসারে রেফারেন্স প্রকারগুলি পাস করা: আপনি ইতিমধ্যে এটি করছেন

সি # ভেরিয়েবলগুলি হয় রেফারেন্স টাইপ বা মান ধরণের । সি # পরামিতি হয় হয় রেফারেন্স দ্বারা পাস হয় বা মান দ্বারা পাস হয় । পরিভাষা এখানে একটি সমস্যা; এই শব্দগুলি একই জিনিসটির মতো, তবে তারা তা নয়।

আপনি যদি কোনও প্রকারের প্যারামিটারটি পাস করেন এবং আপনি refকীওয়ার্ডটি ব্যবহার না করেন তবে আপনি এটি মান দিয়ে পাস করেছেন। যদি আপনি এটি মান দিয়ে পাস করেন তবে আপনি যা যা সত্যই পেরিয়েছেন তা ছিল একটি অনুলিপি। তবে যদি প্যারামিটারটি কোনও রেফারেন্স টাইপ হয়, তবে আপনি যে জিনিসটি অনুলিপি করেছেন সেটি হল রেফারেন্স, এটি যা দেখানো হয়েছিল তা নয়।

Mainপদ্ধতির প্রথম লাইনটি এখানে :

string strMain = "main";

আমরা এই লাইনে দুটি জিনিস তৈরি করেছি: mainকোথাও মেমরিতে সঞ্চিত মান সহ একটি স্ট্রিং , এবং strMainএটি উল্লেখ করার জন্য একটি রেফারেন্স ভেরিয়েবল ।

DoSomething(strMain);

এখন আমরা সেই রেফারেন্সটি পাস করি DoSomething। আমরা এটি মান দিয়ে পাস করেছি, এর অর্থ আমরা একটি অনুলিপি তৈরি করেছি। এটি একটি রেফারেন্সের ধরণ, সুতরাং এর অর্থ আমরা রেফারেন্সটি অনুলিপি করেছি, স্ট্রিংটি নয়। এখন আমাদের দুটি উল্লেখ রয়েছে যা প্রতিটি স্মৃতিতে একই মানের দিকে নির্দেশ করে।

কলির ভিতরে

DoSomethingপদ্ধতির শীর্ষস্থানীয় এখানে :

void DoSomething(string strLocal)

কোনও refকীওয়ার্ড নয়, তাই strLocalএবং strMainদুটি ভিন্ন রেফারেন্স একই মানের দিকে নির্দেশ করছে। আমরা যদি আবার নিয়োগ করি strLocal...

strLocal = "local";   

... আমরা সঞ্চিত মান পরিবর্তন করি নি; আমরা ফোন করা রেফারেন্সটি নিয়েছি এবং একে একে একে একে একে একে একে strLocalনতুন নতুন স্ট্রিংয়ে রেখেছি। strMainআমরা কি যখন কি ঘটবে ? কিছুই নেই। এটি এখনও পুরানো স্ট্রিংয়ের দিকে ইঙ্গিত করছে।

string strMain = "main";    // Store a string, create a reference to it
DoSomething(strMain);       // Reference gets copied, copy gets re-pointed
Console.WriteLine(strMain); // The original string is still "main" 

অপরিবর্তনীয়তা

এক সেকেন্ডের জন্য দৃশ্যপট পরিবর্তন করা যাক। কল্পনা করুন আমরা স্ট্রিং নিয়ে কাজ করছি না, তবে আপনি তৈরি করেছেন এমন শ্রেণীর মতো কিছু পরিবর্তনীয় রেফারেন্স টাইপ।

class MutableThing
{
    public int ChangeMe { get; set; }
}

আপনি যদি নির্দেশিত অবজেক্টের রেফারেন্সটি অনুসরণ করেন তবে আপনি objLocalএর বৈশিষ্ট্যগুলি পরিবর্তন করতে পারেন:

void DoSomething(MutableThing objLocal)
{
     objLocal.ChangeMe = 0;
} 

MutableThingস্মৃতিতে এখনও একটি মাত্র আছে , এবং অনুলিপি করা রেফারেন্স এবং মূল রেফারেন্স উভয়ই এখনও এটি দেখায়। নিজস্ব বৈশিষ্ট্যগুলি MutableThingপরিবর্তিত হয়েছে :

void Main()
{
    var objMain = new MutableThing();
    objMain.ChangeMe = 5; 
    Console.WriteLine(objMain.ChangeMe); // it's 5 on objMain

    DoSomething(objMain);                // now it's 0 on objLocal
    Console.WriteLine(objMain.ChangeMe); // it's also 0 on objMain   
}

আহ, কিন্তু স্ট্রিং অবিচ্ছেদ্য! ChangeMeসেট করার মতো কোনও সম্পত্তি নেই । আপনি strLocal[3] = 'H'সি-স্টাইল charঅ্যারে দিয়ে যেমন করতে পারেন তেমন সি-তে পারবেন না ; পরিবর্তে আপনাকে একটি সম্পূর্ণ নতুন স্ট্রিং তৈরি করতে হবে। পরিবর্তনের একমাত্র উপায় strLocalহ'ল রেফারেন্সটিকে অন্য স্ট্রিংয়ে দেখানো, এবং এর অর্থ আপনি strLocalপ্রভাবিত করতে পারে না এমন কিছুই strMain। মান অপরিবর্তনীয় এবং রেফারেন্সটি একটি অনুলিপি।

রেফারেন্স দ্বারা একটি রেফারেন্স পাস

পার্থক্য প্রমাণ করার জন্য, আপনি যখন রেফারেন্সের মাধ্যমে রেফারেন্সটি পাস করেন তখন কী হয় :

void DoSomethingByReference(ref string strLocal)
{
    strLocal = "local";
}
void Main()
{
    string strMain = "main";
    DoSomethingByReference(ref strMain);
    Console.WriteLine(strMain);          // Prints "local"
}

এবার, স্ট্রিংটি Mainসত্যই পরিবর্তিত হবে কারণ আপনি স্ট্যাকে অনুলিপি না করে রেফারেন্সটি পাস করেছেন।

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

আরও সংস্থানগুলি:


3
@ দ্য লাইট - দুঃখিত, তবে আপনি এখানে ভুল বলেছেন যখন: "একটি রেফারেন্স টাইপ ডিফল্টরূপে রেফারেন্স দ্বারা পাস করা হয়।" ডিফল্টরূপে, সমস্ত পরামিতি মান দ্বারা পাস হয়, তবে রেফারেন্স ধরণের সাথে, এর অর্থ হল রেফারেন্সটি মান দ্বারা পাস করা হয়। আপনি রেফারেন্সের পরামিতিগুলির সাথে রেফারেন্স প্রকারগুলি বিভ্রান্ত করছেন যা বোধগম্য কারণ এটি একটি খুব বিভ্রান্তিমূলক পার্থক্য। দেখুন মূল্য অধ্যায় এখানে দ্বারা রেফারেন্স প্রকারভেদ পাসিং। আপনার লিঙ্ক করা নিবন্ধটি বেশ সঠিক, তবে এটি আসলে আমার বক্তব্যকে সমর্থন করে।
জাস্টিন মরগান

1
@ জাস্টিনমোরগান এএ মৃত মন্তব্যের থ্রেড না আনার জন্য, তবে আমি মনে করি আপনি সি সি-তে যদি মনে করেন তবে ডাইলাইটের মন্তব্যটি বোধগম্য হবে, ডেটা কেবল মেমরির এক ব্লক। একটি রেফারেন্স মেমরির সেই ব্লকের পয়েন্টার। যদি আপনি কোনও ফাংশনে মেমরির পুরো ব্লকটি পাস করেন তবে এটিকে "মান দ্বারা পাসিং" বলা হয়। আপনি যদি পয়েন্টারটি পাস করেন তবে এটিকে "রেফারেন্স দ্বারা পাসিং" বলা হয়। সি # তে, মেমোরির পুরো ব্লকটিতে পাস করার কোনও ধারণা নেই, সুতরাং তারা পয়েন্টারটি পাস করার অর্থ "মান দিয়ে চলে যাওয়া" এর নতুন সংজ্ঞা দেয়। এটি ভুল বলে মনে হয়, তবে পয়েন্টারটিও কেবল স্মৃতিশক্তি of আমার কাছে, পরিভাষাটি বেশ নির্বিচারে
rliu

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

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

2
আপনি সঠিক, কিন্তু আমি মনে করি @roliu উল্লেখ ছিল কিভাবে একটি ফাংশন যেমন Foo(string bar)হিসাবে চিন্তা করা যেতে পারে Foo(char* bar)যেহেতু Foo(ref string bar)হবে Foo(char** bar)(অথবা Foo(char*& bar)বা Foo(string& bar)C ++)। অবশ্যই, এটি আপনাকে প্রতিদিন কীভাবে ভাবা উচিত তা নয়, তবে এটি আসলে আমাকে হুডের নীচে কী ঘটছে তা বুঝতে সাহায্য করেছে।
কোল জনসন

23

সি # তে স্ট্রিংগুলি পরিবর্তনযোগ্য রেফারেন্স অবজেক্ট। এর অর্থ হ'ল তাদের কাছে উল্লেখগুলি (মান অনুসারে) প্রায় পাশ করা হয় এবং একবার স্ট্রিং তৈরি হয়ে গেলে আপনি এটিকে পরিবর্তন করতে পারবেন না। স্ট্রিংয়ের পরিবর্তিত সংস্করণগুলি তৈরি করার পদ্ধতিগুলি (সাবস্ট্রিংগুলি, ছাঁটাই করা সংস্করণগুলি ইত্যাদি) মূল স্ট্রিংয়ের পরিবর্তিত অনুলিপি তৈরি করে ।


10

স্ট্রিংগুলি বিশেষ ক্ষেত্রে। প্রতিটি উদাহরণ অপরিবর্তনীয়। আপনি যখন স্ট্রিংয়ের মান পরিবর্তন করেন আপনি মেমরিতে একটি নতুন স্ট্রিং বরাদ্দ করছেন।

সুতরাং কেবলমাত্র আপনার ফাংশনে রেফারেন্সটি প্রেরণ করা হবে তবে স্ট্রিংটি সম্পাদিত হয়ে গেলে এটি একটি নতুন উদাহরণ হয়ে যায় এবং পুরানো দৃষ্টান্তটি পরিবর্তন করে না।


4
স্ট্রিংগুলি এই দিকটিতে কোনও বিশেষ ক্ষেত্রে নয় । অপরিবর্তনীয় বস্তু তৈরি করা খুব সহজ, যা একই শব্দার্থক হতে পারে। (এটি, কোনও ধরণের উদাহরণ যা এটির পরিবর্তনের কোনও পদ্ধতি প্রকাশ করে না ...)

স্ট্রিংগুলি বিশেষ ক্ষেত্রে - এগুলি কার্যকরভাবে অপরিবর্তনীয় রেফারেন্স ধরণের যা তারা মান ধরণের মতো আচরণ করে এমন পরিবর্তনীয় বলে মনে হয়।
Enigmativity

1
@ দক্ষতা সেই যুক্তি অনুসারে তখন Uri(শ্রেণি) এবং Guid( কাঠামোগত ) এছাড়াও বিশেষ ঘটনা। System.Stringশ্রেণিবদ্ধ বা কাঠামো উত্পন্ন অন্য অপরিবর্তনীয় প্রকারের চেয়ে "মান টাইপ" এর মতো কীভাবে কাজ করে তা আমি দেখতে পাই না ।

3
@pst - স্ট্রিংস বিশেষ সৃষ্টি শব্দার্থবিদ্যা আছে - অসদৃশ Uri& Guid- আপনি অবশ্য একটি স্ট্রিং পরিবর্তনশীল করার জন্য একটি স্ট্রিং-আক্ষরিক মান ধার্য করতে পারেন। স্ট্রিংটি intপুনঃনির্ধারিত হওয়ার মতো পরিবর্তিত হতে পারে বলে মনে হচ্ছে তবে এটি কোনও স্পষ্টতই কোনও বস্তু তৈরি করছে - কোনও newকীওয়ার্ড নেই।
বৈশ্বিকতা

3
স্ট্রিং একটি বিশেষ কেস তবে এটির এই প্রশ্নের কোনও মিল নেই। মান প্রকার, রেফারেন্সের ধরণ, যাই হোক না কেন প্রকারের সমস্ত এই প্রশ্নের একই কাজ করবে।
কર્ક ব্রডহর্স্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.