# + = Over এর জন্য সি # অপারেটর ওভারলোড?


114

আমি এর জন্য অপারেটর ওভারলোডগুলি করার চেষ্টা করছি +=, কিন্তু পারছি না। আমি কেবল অপারেটরকে ওভারলোড করতে পারি +

কিভাবে?

সম্পাদন করা

এটি কাজ না করার কারণটি হ'ল আমার একটি ভেক্টর শ্রেণি রয়েছে (একটি এক্স এবং ওয়াই ফিল্ড সহ)। নিম্নলিখিত উদাহরণ বিবেচনা করুন।

vector1 += vector2;

যদি আমার অপারেটর ওভারলোডটি সেট করা থাকে:

public static Vector operator +(Vector left, Vector right)
{
    return new Vector(right.x + left.x, right.y + left.y);
}

তারপরে ফলাফলটি ভেক্টর 1 এ যুক্ত করা হবে না, তবে পরিবর্তে, ভেক্টর 1 পাশাপাশি রেফারেন্স হিসাবে একটি ব্র্যান্ড নিউ ভেক্টর হয়ে উঠবে।


2
দেখে মনে হচ্ছে এই সম্পর্কে ইতিমধ্যে একটি দীর্ঘ আলোচনা হয়ে গেছে: maurits.wordpress.com/2006/11/27/…
ক্রিস এস

39
আপনি কেন এটি করার চেষ্টা করছেন তা ব্যাখ্যা করতে পারেন? আপনি যখন ওভারলোড "+" করেন তখন আপনি ওভারলোডেড "+ =" অপারেটরটি নিখরচায় পাবেন। কিছু অবস্থা যা এটি কি আপনি কি চাই "+ + =" ওভারলোড হয়ে কিন্তু কি না , "+" ওভারলোড হয়ে করতে চান?
এরিক লিপার্ট

3
সি ++ থেকে আগত, এটি কেবল ভুল অনুভব করে তবে সি # এ আসলে নিখুঁত ধারণা দেয়।
জন পুর্ডি


12
@ ম্যাথিয়াস: আপনার আপডেট: পুনরুদ্ধারকারীদের অপরিবর্তনীয় গাণিতিক বিষয়গুলির মতো আচরণ করা উচিত। আপনি 2 থেকে 3 যোগ করার সময়, আপনি বস্তুকে 3 অবজেক্টে রূপান্তর করবেন না 5 আপনি সম্পূর্ণ নতুন অবজেক্ট তৈরি করেন, ৫. অতিরিক্ত লোডিং অপারেটরগুলির বিন্দুটি আপনার নিজের গাণিতিক অবজেক্টগুলি তৈরি করা হয়; তাদের এই উদ্দেশ্যটির বিপরীতে পরিবর্তনীয় কাজ করা। আমি আপনার ভেক্টর টাইপ একটি অপরিবর্তনযোগ্য মান প্রকার করতে হবে।
এরিক লিপার্ট

উত্তর:


147

এমএসডিএন থেকে ওভারলোডযোগ্য অপারেটরগুলি :

অ্যাসাইনমেন্ট অপারেটরগুলি ওভারলোড করা যায় না, তবে +=উদাহরণস্বরূপ, ব্যবহার করে মূল্যায়ন করা হয় +, যা ওভারলোড করা যায়।

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

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

এই সাধারণ কোডটি দেখুন:

Decimal d = 10M;
d = d + 10M;
Console.WriteLine(d);

এই নির্দেশাবলীর জন্য আইএল-কোডটি দেখতে দিন:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldc.i4.s   10
  IL_000c:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0011:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal,
                                                                                                valuetype [mscorlib]System.Decimal)
  IL_0016:  stloc.0

এখন এই কোডটি দেখতে দিন:

Decimal d1 = 10M;
d1 += 10M;
Console.WriteLine(d1);

এবং এর জন্য আইএল-কোড:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  ldc.i4.s   10
  IL_000c:  newobj     instance void [mscorlib]System.Decimal::.ctor(int32)
  IL_0011:  call       valuetype [mscorlib]System.Decimal [mscorlib]System.Decimal::op_Addition(valuetype [mscorlib]System.Decimal,
                                                                                                valuetype [mscorlib]System.Decimal)
  IL_0016:  stloc.0

তারা সমান! সুতরাং +=অপারেটর সি # তে আপনার প্রোগ্রামের জন্য কেবল সিনট্যাকটিক চিনি এবং আপনি কেবল +অপারেটরকে ওভারলোড করতে পারেন ।

উদাহরণ স্বরূপ:

class Foo
{
    private int c1;

    public Foo(int c11)
    {
        c1 = c11;
    }

    public static Foo operator +(Foo c1, Foo x)
    {
        return new Foo(c1.c1 + x.c1);
    }
}

static void Main(string[] args)
{
    Foo d1 =  new Foo (10);
    Foo d2 = new Foo(11);
    d2 += d1;
}

এই কোডটি সংকলিত হবে এবং সাফল্যের সাথে চালানো হবে:

  IL_0000:  nop
  IL_0001:  ldc.i4.s   10
  IL_0003:  newobj     instance void ConsoleApplication2.Program/Foo::.ctor(int32)
  IL_0008:  stloc.0
  IL_0009:  ldc.i4.s   11
  IL_000b:  newobj     instance void ConsoleApplication2.Program/Foo::.ctor(int32)
  IL_0010:  stloc.1
  IL_0011:  ldloc.1
  IL_0012:  ldloc.0
  IL_0013:  call       class ConsoleApplication2.Program/Foo ConsoleApplication2.Program/Foo::op_Addition(class ConsoleApplication2.Program/Foo,
                                                                                                          class ConsoleApplication2.Program/Foo)
  IL_0018:  stloc.1

হালনাগাদ:

আপনার আপডেট অনুসারে - @ এরিকলিপার্ট যেমন বলেছে, সত্যিই আপনার অপরিবর্তনীয় বস্তু হিসাবে ভেক্টর থাকা উচিত। দুটি ভেক্টর যুক্ত করার ফলাফল একটি নতুন ভেক্টর, বিভিন্ন আকারের প্রথমটি নয়।

যদি কোনও কারণে আপনাকে প্রথমে ভেক্টর পরিবর্তন করতে হয় তবে আপনি এই ওভারলোডটি ব্যবহার করতে পারেন (তবে আমার কাছে এটি খুব আশ্চর্যজনক আচরণ):

public static Vector operator +(Vector left, Vector right)
{
    left.x += right.x;
    left.y += right.y;
    return left;
}

2
উল্লেখ করে যে ঘটনাটি কেন এটির উত্তর দিচ্ছে না।
জৌকে ভ্যান ডার ম্যাস

1
@ জোউক ভ্যান ডার মাআস এবং আপনি কীভাবে আমাকে উত্তর দিতে চান কেন এটি সম্ভব হচ্ছে না? ডিজাইনে এটি অসম্ভব, আমি আর কী বলব?
ভিএমএটিএম

2
কেন তারা এটিকে এভাবে ডিজাইন করেছে; সত্যিই প্রশ্নটি এটাই। অন্যান্য উত্তর দেখুন।
জৌকে ভ্যান ডার ম্যাস

2
"অদ্ভুত আচরণ" কেবলমাত্র যদি আপনি সি #: পি তে "জন্মগ্রহণ" প্রোগ্রামিং হয়ে থাকেন। তবে, যেহেতু উত্তরটি সঠিক এবং খুব ভালভাবে ব্যাখ্যা করা হয়েছে, আপনি আমার +1ও পাবেন;)
থান্ডারগ্রি

5
@ থান্ডারগ্রি না, আপনি যে ভাষাটি দেখছেন তা মোটেই আশ্চর্যজনক নয়। বিবৃতি করতে v3 = v1 + v2;এ ফলাফলের v1পাশাপাশি পরিবর্তন হচ্ছে v3অস্বাভাবিক
Assimilater

17

আমি মনে করি আপনি এই লিঙ্কটি তথ্যপূর্ণ পাবেন: ওভারলোডযোগ্য অপারেটর

অ্যাসাইনমেন্ট অপারেটরগুলি ওভারলোড করা যায় না, তবে + =, উদাহরণস্বরূপ, + ব্যবহার করে মূল্যায়ন করা হয়, যা ওভারলোড করা যায়।


2
@ পিকপিজি - এই মন্তব্যটি এই থ্রেডের সাথে সম্পর্কিত নয়: দয়া করে আপনার উত্তরটি মুছে ফেলুন, এটি আমার প্রশ্নের উত্তর দেয়, আমি মনে করি আপনার পদ্ধতিটি ব্যবহার করা ছাড়া আমার আর কোনও উপায় নেই, আমি ভেবেছিলাম এটি সমাধানের আরও ভাল উপায় আছে।
শিমি ওয়েইটস্যান্ডলার

16

এটি একই কারণে অ্যাসাইনমেন্ট অপারেটরকে ওভারলোড করা যায় না। আপনি সঠিকভাবে অ্যাসাইনমেন্টটি সম্পাদন করতে পারে এমন কোড লিখতে পারবেন না।

class Foo
{
   // Won't compile.
   public static Foo operator= (Foo c1, int x)
   {
       // duh... what do I do here?  I can't change the reference of c1.
   }
}

অ্যাসাইনমেন্ট অপারেটরগুলি ওভারলোড করা যায় না, তবে + =, উদাহরণস্বরূপ, + ব্যবহার করে মূল্যায়ন করা হয়, যা ওভারলোড করা যায়।

এমএসডিএন থেকে ।


16

আপনি ওভারলোড করতে পারবেন না +=কারণ এটি সত্যই কোনও অনন্য অপারেটর নয়, এটি কেবল সিনট্যাকটিক চিনিx += yলেখার একটি সংক্ষিপ্ত উপায় x = x + y। কারণ এবং অপারেটরদের +=ক্ষেত্রে সংজ্ঞায়িত করা হয়েছে , আপনাকে পৃথকভাবে এটিকে ওভাররাইড করার অনুমতি দেওয়ার ফলে সমস্যা তৈরি হতে পারে, যেখানে ও ঠিক একইভাবে আচরণ করা হয়নি।+=x += yx = x + y

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

আমি বুঝতে পারি যে আপনি এটি একটি পৃথক ক্রিয়াকলাপের মতো চিকিত্সা করতে চাইতে পারেন: x += 10আপনার মতো বিবৃতিতে আপনি জানেন যে আপনি পুরানো রেফারেন্সটি বরাদ্দ করার আগে xকোনও নতুন অবজেক্ট তৈরির পরিবর্তে কোনও স্থানে স্থান পরিবর্তন করতে পারেন এবং সম্ভবত কিছু সময় / স্মৃতি সাশ্রয় করতে পারবেন x + 10

তবে এই কোডটি বিবেচনা করুন:

a = ...
b = a;
a += 10;

উচিত a == bশেষে? বেশিরভাগ ধরণের ক্ষেত্রে, না, a10 এর চেয়ে বেশি b। তবে আপনি যদি +=জায়গায় পরিবর্তনের জন্য অপারেটরটিকে ওভারলোড করতে পারেন তবে হ্যাঁ। এখন এটি বিবেচনা করুন aএবং bপ্রোগ্রামের দূরবর্তী অংশগুলিতে ঘুরে আসতে পারেন। আপনার সম্ভাব্য অপ্টিমাইজেশন বিভ্রান্তিকর বাগ তৈরি করতে পারে যদি কোডটি এটির প্রত্যাশা না করে যেখানে আপনার অবজেক্টটি পরিবর্তন হতে শুরু করে।

অন্য কথায়, যদি পারফরম্যান্সটি গুরুত্বপূর্ণ, তবে x += 10কোনও মেথড কলের মতো প্রতিস্থাপন করা খুব বেশি কঠিন নয় x.increaseBy(10)এবং জড়িত প্রত্যেকের পক্ষে এটি আরও পরিষ্কার।


2
ব্যক্তিগতভাবে, আমি পরিবর্তন it's just syntactic sugarকরতে হবে it's just syntactic sugar in C#; অন্যথায়, এটি খুব সাধারণ শোনায়, তবে কিছু প্রোগ্রামিং ভাষায়, এটি কেবল সিনট্যাকটিক চিনি নয়, তবে এটি সম্ভবত কর্মক্ষমতা সুবিধা দেয়।
সেবাস্তিয়ান মাচ

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

@ সেবাস্তিয়ানম্যাচ প্রশ্নটি বিশেষত সি # এবং ডটনেট ট্যাগ দিয়ে ট্যাগ করা হয়েছে। স্পষ্টতই, সি ++ এ উদাহরণস্বরূপ, '+' এবং '+ =' (এবং এমনকি '=') আলাদাভাবে ওভারলোড করা যায়।
বোজিদার স্টানচেভ

1
@ বুজিদারস্টাচেভ: সত্য। আমি আমার 9 বছরের ছোট আত্মার জন্য ক্ষমা চাইছি :
সেবাস্তিয়ান মাচ

9

এটি কারণ এই অপারেটরটি ওভারলোড করা যায় না:

অ্যাসাইনমেন্ট অপারেটরগুলি ওভারলোড করা যায় না, তবে + =, উদাহরণস্বরূপ, + ব্যবহার করে মূল্যায়ন করা হয়, যা ওভারলোড করা যায়।

দুটিই MSDN

শুধু ওভারলোড +অপারেটর, কারণ

x += y সমান x = x + y



6

আপনি যদি এটির +মতো ওভারলোড করেন :

class Foo
{
    public static Foo operator + (Foo c1, int x)
    {
        // implementation
    }
}

আপনি করতে পারেন

 Foo foo = new Foo();
 foo += 10;

অথবা

 foo = foo + 10;

এটি সংকলন এবং সমানভাবে চলবে।


6

এই সমস্যাটির সর্বদা একই উত্তর রয়েছে: +=আপনি যদি ওভারলোড করে থাকেন তবে তা নিখরচায় পেলে আপনার কী দরকার +। তবে আমার মতো ক্লাস থাকলে কী হয়।

using System;
using System.IO;

public class Class1
{
    public class MappableObject
    {
        FileStream stream;

        public  int Blocks;
        public int BlockSize;

        public MappableObject(string FileName, int Blocks_in, int BlockSize_in)
        {
            Blocks = Blocks_in;
            BlockSize = BlockSize_in;

            // Just create the file here and set the size
            stream = new FileStream(FileName); // Here we need more params of course to create a file.
            stream.SetLength(sizeof(float) * Blocks * BlockSize);
        }

        public float[] GetBlock(int BlockNo)
        {
            long BlockPos = BlockNo * BlockSize;

            stream.Position = BlockPos;

            using (BinaryReader reader = new BinaryReader(stream))
            {
                float[] resData = new float[BlockSize];
                for (int i = 0; i < BlockSize; i++)
                {
                    // This line is stupid enough for accessing files a lot and the data is large
                    // Maybe someone has an idea to make this faster? I tried a lot and this is the simplest solution
                    // for illustration.
                    resData[i] = reader.ReadSingle();
                }
            }

            retuen resData;
        }

        public void SetBlock(int BlockNo, float[] data)
        {
            long BlockPos = BlockNo * BlockSize;

            stream.Position = BlockPos;

            using (BinaryWriter reader = new BinaryWriter(stream))
            {
                for (int i = 0; i < BlockSize; i++)
                {
                    // Also this line is stupid enough for accessing files a lot and the data is large
                    reader.Write(data[i];
                }
            }

            retuen resData;
        }

        // For adding two MappableObjects
        public static MappableObject operator +(MappableObject A, Mappableobject B)
        {
            // Of course we have to make sure that all dimensions are correct.

            MappableObject result = new MappableObject(Path.GetTempFileName(), A.Blocks, A.BlockSize);

            for (int i = 0; i < Blocks; i++)
            {
                float[] dataA = A.GetBlock(i);
                float[] dataB = B.GetBlock(i);

                float[] C = new float[dataA.Length];

                for (int j = 0; j < BlockSize; j++)
                {
                    C[j] = A[j] + B[j];
                }

                result.SetBlock(i, C);
            }
        }

        // For adding a single float to the whole data.
        public static MappableObject operator +(MappableObject A, float B)
        {
            // Of course we have to make sure that all dimensions are correct.

            MappableObject result = new MappableObject(Path.GetTempFileName(), A.Blocks, A.BlockSize);

            for (int i = 0; i < Blocks; i++)
            {
                float[] dataA = A.GetBlock(i);

                float[] C = new float[dataA.Length];

                for (int j = 0; j < BlockSize; j++)
                {
                    C[j] = A[j] + B;
                }

                result.SetBlock(i, C);
            }
        }

        // Of course this doesn't work, but maybe you can see the effect here.
        // when the += is automimplemented from the definition above I have to create another large
        // object which causes a loss of memory and also takes more time because of the operation -> altgough its
        // simple in the example, but in reality it's much more complex.
        public static MappableObject operator +=(MappableObject A, float B)
        {
            // Of course we have to make sure that all dimensions are correct.

            MappableObject result = new MappableObject(Path.GetTempFileName(), A.Blocks, A.BlockSize);

            for (int i = 0; i < Blocks; i++)
            {
                float[] dataA = A.GetBlock(i);

                for (int j = 0; j < BlockSize; j++)
                {
                    A[j]+= + B;
                }

                result.SetBlock(i, A);
            }
        }
    }
}

আপনি কি এখনও বলছেন যে এটি +="স্বতঃ-বাস্তবায়িত" ভাল। আপনি যদি সি # তে উচ্চ-পারফরম্যান্স কম্পিউটিং করার চেষ্টা করেন আপনার প্রসেসিং সময় এবং মেমরির খরচ হ্রাস করার জন্য এই জাতীয় বৈশিষ্ট্যগুলি থাকা দরকার, যদি কারওর ভাল সমাধান থাকে তবে এটির প্রশংসা করা হয়, তবে আমাকে বলবেন না আমাকে স্থির পদ্ধতিতে এটি করতে হবে , এটি কেবলমাত্র এক কর্মক্ষেত্র এবং আমি সি # +=সংজ্ঞায়িত না হলে প্রয়োগটি কার্যকর করার কোনও কারণ দেখি না এবং যদি এটি সংজ্ঞায়িত করা হয় তবে এটি ব্যবহার করা হবে। কিছু লোক বলে যে এর মধ্যে পার্থক্য না থাকা +এবং +=ত্রুটিগুলি রোধ করে তবে এটি কি আমার নিজের সমস্যা নয়?


2
আপনি যদি সত্যই পারফরম্যান্সের বিষয়ে চিন্তা করেন তবে আপনি অপারেটর ওভারলোডিং নিয়ে গোলমাল করবেন না, যা কোন কোডটি চাওয়া হচ্ছে তা বলা কেবল আরও শক্ত করে তোলে। এর অর্থার্থকে গণ্ডগোল করা +=আপনার নিজের সমস্যা কিনা ... এটি কেবল সত্য যদি অন্য কারও কাছে আপনার কোডটি পড়তে, রক্ষণাবেক্ষণ করতে বা চালিত করতে না হয়।
বেনজাদো

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

2
ইঞ্জিনিয়ারিং ট্রেড অফস সম্পর্কে; আপনি যা চান তা দামের সাথে আসে।
বেনজাদো

3
পাটিগণিত অপারেটররা কনভেনশন করে নতুন দৃষ্টান্ত ফেরত দেয় - তাই এগুলি সাধারণত অপরিবর্তনীয় ধরণের ক্ষেত্রে ওভাররাইড করা হয়। উদাহরণস্বরূপ, List<T>অপারেটর ব্যবহার করে আপনি কোনও নতুন উপাদান যুক্ত করতে পারবেন না list += "new item"Addপরিবর্তে আপনি এর পদ্ধতি কল ।
akafak Gür


0

আরও ভাল নকশা পদ্ধতি হ'ল সুস্পষ্ট কাস্টিং। আপনি অবশ্যই কাস্টিংকে ওভারলোড করতে পারেন।

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