রেফারেন্স বা সি # তে মান দ্বারা অবজেক্টগুলি পাস করা


233

সি # তে, আমি সর্বদা ভেবেছি যে অ-আদিম পরিবর্তনগুলি রেফারেন্স দ্বারা এবং আদিম মানগুলি মান দ্বারা পাস হয়েছিল।

সুতরাং যখন কোনও পদ্ধতিতে কোনও অ-আদিম বস্তু পাস করার সময়, পদ্ধতিতে অবজেক্টটির সাথে যে কোনও কিছু করা বস্তুটির পাস হওয়ার ক্ষেত্রে প্রভাব ফেলবে। (সি # 101 স্টাফ)

যাইহোক, আমি লক্ষ্য করেছি যে আমি যখন একটি সিস্টেম.ড্রয়িং.ইমজ অবজেক্টটি পাস করি তখন এটি মনে হয় না? আমি যদি অন্য পদ্ধতিতে একটি system.drawing.image অবজেক্টটি পাস করি এবং সেই বস্তুর উপর একটি চিত্র লোড করি, তবে সেই পদ্ধতিটি সুযোগের বাইরে চলে যাক এবং কলিং পদ্ধতিতে ফিরে যেতে দিন, সেই চিত্রটি আসল অবজেক্টে লোড হয় না?

কেন?


20
সমস্ত পরিবর্তনশীল সি # তে ডিফল্টরূপে মান দ্বারা পাস হয় are আপনি রেফারেন্স ধরণের ক্ষেত্রে রেফারেন্সের মানটি পাস করছেন
অ্যান্ড্রু বার্বার

উত্তর:


502

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

আপনি পাস-বাই-রেফারেন্স ব্যবহার করতে চান, তাহলে আপনি আবশ্যক ব্যবহার outবা refকিনা প্যারামিটার প্রকার একটি মান টাইপ বা একটি রেফারেন্স প্রকার। সেক্ষেত্রে কার্যকরভাবে পরিবর্তনশীল নিজেই রেফারেন্সের মাধ্যমে পাস হয়, সুতরাং প্যারামিটারটি আর্গুমেন্টের মতো একই স্টোরেজ অবস্থান ব্যবহার করে - এবং প্যারামিটারে নিজেই পরিবর্তনকারীকে দেখা যায়।

তাই:

public void Foo(Image image)
{
    // This change won't be seen by the caller: it's changing the value
    // of the parameter.
    image = Image.FromStream(...);
}

public void Foo(ref Image image)
{
    // This change *will* be seen by the caller: it's changing the value
    // of the parameter, but we're using pass by reference
    image = Image.FromStream(...);
}

public void Foo(Image image)
{
    // This change *will* be seen by the caller: it's changing the data
    // within the object that the parameter value refers to.
    image.RotateFlip(...);
}

আমার একটি নিবন্ধ রয়েছে যা এটিতে আরও অনেক বিস্তৃত । মূলত, "রেফারেন্স দ্বারা পাস" এর অর্থ এটির অর্থ কী তা বোঝায় না।


2
তোমার অধিকার, আমি তা দেখতে পাইনি! আমি ইমেজ = চিত্র.ফর্মফায়াল (..) লোড করছি এবং এটি চলক চিত্রটি প্রতিস্থাপন করছে এবং অবজেক্টটি পরিবর্তন করছে না! :) অবশ্যই.
মাইকেল

1
@ আদিম: একেবারে নয় - কোনও "প্যারামিটার অবজেক্ট" নেই, এমন কোনও জিনিস রয়েছে যা প্যারামিটারের মান বোঝায়। আমি মনে করি আপনি সঠিক ধারণা পেয়েছেন, তবে পরিভাষাটি গুরুত্বপূর্ণ :)
জন স্কিটি

2
যদি আমরা কীওয়ার্ড refএবং outসি # থেকে ড্রপ করি তবে এটি কি ঠিক বলা যায় যে সি # প্যারামিটারগুলি জাভা যেমন অর্থ সর্বদা মান অনুসারে পাস করে passes জাভা নিয়ে কি কোনও পার্থক্য আছে?
ব্রডব্যান্ড

1
@ ব্রডব্যান্ড: হ্যাঁ, ডিফল্ট পাসিং মোডটি বাই-ভ্যালু। যদিও অবশ্যই সি # এর পয়েন্টার এবং কাস্টম মান ধরণের রয়েছে যা এটি জাভার চেয়ে কিছুটা জটিল করে তোলে।
জন স্কিটি

3
@ ভিপ্পি: না, একদম নয়। এটি রেফারেন্সের একটি অনুলিপি । আমি আপনাকে লিঙ্কিত নিবন্ধটি পড়ার পরামর্শ দিচ্ছি।
জন স্কিটি

18

এটি প্রদর্শনের জন্য আরও একটি কোড নমুনা:

void Main()
{


    int k = 0;
    TestPlain(k);
    Console.WriteLine("TestPlain:" + k);

    TestRef(ref k);
    Console.WriteLine("TestRef:" + k);

    string t = "test";

    TestObjPlain(t);
    Console.WriteLine("TestObjPlain:" +t);

    TestObjRef(ref t);
    Console.WriteLine("TestObjRef:" + t);
}

public static void TestPlain(int i)
{
    i = 5;
}

public static void TestRef(ref int i)
{
    i = 5;
}

public static void TestObjPlain(string s)
{
    s = "TestObjPlain";
}

public static void TestObjRef(ref string s)
{
    s = "TestObjRef";
}

এবং আউটপুট:

TestPlain: 0

TestRef: 5

TestObjPlain: পরীক্ষা

TestObjRef: TestObjRef


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

1
স্ট্রিংগুলি পরিবর্তনযোগ্য রেফারেন্স ধরণের types অপরিবর্তনীয় অর্থ, এটি তৈরির পরে এটি পরিবর্তন করা যায় না। স্ট্রিংয়ের প্রতিটি পরিবর্তন একটি নতুন স্ট্রিং তৈরি করবে। এজন্য কল করার পদ্ধতিতে পরিবর্তন পেতে স্ট্রিংগুলিকে 'রেফ' হিসাবে পাস করতে হবে। কলিং পদ্ধতিতে পরিবর্তনগুলি ফিরে পেতে অন্যান্য অবজেক্ট (যেমন কর্মচারী) 'রেফ' ছাড়াই পাস করা যায়।
হিমালয় গার্গ

1
@vmg, হিমালয়গার্গ অনুসারে, এটি খুব ভাল উদাহরণ নয়। আপনাকে অন্য একটি রেফারেন্স ধরণের উদাহরণ অন্তর্ভুক্ত করতে হবে যা অপরিবর্তনীয় নয়।
ড্যানিয়েল

11

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

আপনি যখন কোনও পদ্ধতির পক্ষে আর্গুমেন্ট হিসাবে কোনও উদাহরণটি পাস করেন copyএটি উদাহরণের পাস করে । এখন, আপনি যে উদাহরণটি পাস করেছেন তা যদি সেই মানটির অনুলিপিটি পাস করে value typeতবে ( যদি আপনি এটি পরিবর্তন করেন), এটি কলারের মধ্যে প্রতিফলিত হবে না। উদাহরণটি যদি কোনও রেফারেন্স টাইপ হয় তবে আপনি রেফারেন্সের অনুলিপিটি (আবার এতে বাস করেন ) অবজেক্টে পাস করুন । সুতরাং আপনি একই জিনিস দুটি রেফারেন্স পেয়েছি। উভয়ই বস্তুটি সংশোধন করতে পারে। তবে যদি পদ্ধতিটির অভ্যন্তরে, আপনি নতুন অবজেক্টটি ইনস্ট্যান্ট করবেন আপনার রেফারেন্সের অনুলিপিটি আর কোনও আসল বস্তুর জন্য উল্লেখ করবে না, এটি আপনার সদ্য নির্মিত নতুন অবজেক্টটিকে উল্লেখ করবে। সুতরাং আপনি 2 রেফারেন্স এবং 2 অবজেক্ট সমাপ্ত হবে।stackstack


এটি নির্বাচিত উত্তর হওয়া উচিত!
জেএএন

অামি সম্পূর্ণ একমত! :)
JOSEFtw

8

আপনি যখন এটির মতো করেন তখন আমার স্পষ্ট ধারণা। আমি এই জাতীয় জিনিস পরীক্ষা করার জন্য লিনকপ্যাড ডাউনলোড করার পরামর্শ দিই

void Main()
{
    var Person = new Person(){FirstName = "Egli", LastName = "Becerra"};

    //Will update egli
    WontUpdate(Person);
    Console.WriteLine("WontUpdate");
    Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");

    UpdateImplicitly(Person);
    Console.WriteLine("UpdateImplicitly");
    Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");

    UpdateExplicitly(ref Person);
    Console.WriteLine("UpdateExplicitly");
    Console.WriteLine($"First name: {Person.FirstName}, Last name: {Person.LastName}\n");
}

//Class to test
public class Person{
    public string FirstName {get; set;}
    public string LastName {get; set;}

    public string printName(){
        return $"First name: {FirstName} Last name:{LastName}";
    }
}

public static void WontUpdate(Person p)
{
    //New instance does jack...
    var newP = new Person(){FirstName = p.FirstName, LastName = p.LastName};
    newP.FirstName = "Favio";
    newP.LastName = "Becerra";
}

public static void UpdateImplicitly(Person p)
{
    //Passing by reference implicitly
    p.FirstName = "Favio";
    p.LastName = "Becerra";
}

public static void UpdateExplicitly(ref Person p)
{
    //Again passing by reference explicitly (reduntant)
    p.FirstName = "Favio";
    p.LastName = "Becerra";
}

এবং যে আউটপুট করা উচিত

WontUpdate

প্রথম নাম: এগলি, শেষ নাম: বেরেরেরা

UpdateImplicitly

প্রথম নাম: ফ্যাভিও, শেষ নাম: বেরেরেরা

UpdateExplicitly

প্রথম নাম: ফ্যাভিও, শেষ নাম: বেরেরেরা


এবং পাবলিক স্ট্যাটিক অকার্যকর সম্পর্কে কী কী (ব্যক্তি পি) out পি = নতুন ব্যক্তি () {প্রথম নাম = "প্রথম", লাস্টনাম = "শেষ"}; । :)
মেরিন পপভ

4

আপনি যখন System.Drawing.Imageকোনও পদ্ধতিতে টাইপ অবজেক্টটি পাস করেন আপনি আসলে সেই অবজেক্টের রেফারেন্সের একটি অনুলিপি পাস করছেন।

সুতরাং যদি সেই পদ্ধতির অভ্যন্তরে আপনি কোনও নতুন চিত্র লোড করছেন তবে আপনি নতুন / অনুলিপিযুক্ত রেফারেন্স ব্যবহার করে লোড করছেন। আপনি আসল পরিবর্তন করছেন না।

YourMethod(System.Drawing.Image image)
{
    //now this image is a new reference
    //if you load a new image 
    image = new Image()..
    //you are not changing the original reference you are just changing the copy of original reference
}

2

পদ্ধতিতে আপনি কীভাবে আপত্তিটি পাস করেছেন?

আপনি কি বস্তুর জন্য সেই পদ্ধতির ভিতরে নতুন করছেন? যদি তা হয় তবে আপনাকে refপদ্ধতিতে ব্যবহার করতে হবে ।

নিম্নলিখিত লিঙ্কটি আপনাকে আরও ভাল ধারণা দেয়।

http://dotnetstep.blogspot.com/2008/09/passing-reference-type-byval-or-byref.html


-1

রেফারেন্স রেফারেন্সে আপনি কেবলমাত্র ফাংশন প্যারামিটারগুলিতে "রেফ" যুক্ত করুন এবং মূল বিষয়টির কারণে আপনাকে আরও একটি জিনিস "স্ট্যাটিক" হিসাবে ঘোষণা করতে হবে যা স্থির (# public void main(String[] args))!

namespace preparation
{
  public  class Program
    {
      public static void swap(ref int lhs,ref int rhs)
      {
          int temp = lhs;
          lhs = rhs;
          rhs = temp;
      }
          static void Main(string[] args)
        {
            int a = 10;
            int b = 80;

  Console.WriteLine("a is before sort " + a);
            Console.WriteLine("b is before sort " + b);
            swap(ref a, ref b);
            Console.WriteLine("");
            Console.WriteLine("a is after sort " + a);
            Console.WriteLine("b is after sort " + b);  
        }
    }
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.