program tip

`+ =`에 대한 C # 연산자 과부하?

radiobox 2020. 8. 5. 08:05
반응형

`+ =`에 대한 C # 연산자 과부하?


에 대한 연산자 오버로드를 시도하고 +=있지만 할 수 없습니다. 에 대한 연산자 오버로드 만 만들 수 있습니다 +.

어떻게 오세요?

편집하다

이것이 작동하지 않는 이유는 Vector 클래스 (X 및 Y 필드 포함)가 있기 때문입니다. 다음 예를 고려하십시오.

vector1 += vector2;

운영자 과부하가 다음으로 설정된 경우 :

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

그러면 결과가 vector1에 추가되지 않고 대신 vector1이 참조로 새로운 Vector가됩니다.


MSDN의 과부하 연산자 :

할당 연산자는 오버로드 될 수 없지만 +=예를 들어을 사용하여 +오버로드 될 수있는을 사용하여 평가됩니다 .

또한 할당 연산자 중 어느 것도 오버로드 될 수 없습니다. CLR 강력한 유형 세계에서 잠재적 인 보안 허점 인 가비지 수집 및 메모리 관리에 영향을 미칠 것이기 때문이라고 생각합니다.

그럼에도 불구하고 정확히 연산자가 무엇인지 봅시다. 유명한 Jeffrey Richter의 저서 에 따르면 , 각 프로그래밍 언어에는 고유 한 연산자 목록이 있으며 특수 메소드 호출로 컴파일되며 CLR 자체는 연산자에 대해 아무것도 모릅니다. 따라서 +and +=연산자 뒤에 정확히 무엇이 있는지 살펴 보겠습니다 .

이 간단한 코드를 참조하십시오 :

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

이 지침에 대한 IL 코드를 확인하십시오.

  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 코드 :

  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

그들은 평등하다! 따라서 +=연산자는 C # 의 프로그램 대한 구문 설탕 일 뿐이며 +연산자를 단순히 오버로드 할 수 있습니다 .

예를 들면 다음과 같습니다.

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

최신 정보:

업데이트에 따르면 @EricLippert에서 알 수 있듯이 벡터는 불변 개체로 있어야합니다. 두 벡터를 더한 결과는 크기가 다른 첫 벡터가 아닌 벡터입니다.

어떤 이유로 든 첫 번째 벡터를 변경 해야하는 경우이 과부하를 사용할 수 있습니다 (그러나 저에게는 매우 이상한 행동입니다).

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

나는 당신 이이 링크를 유익하게 찾을 것이라고 생각합니다 : 과부하 연산자

할당 연산자는 오버로드 될 수 없지만 + =는 +를 사용하여 평가되며, 오버로드 될 수 있습니다.


+=실제로 고유 한 연산자가 아니기 때문에 오버로드 할 수 없으며 구문 설탕 일뿐 입니다. x += y단지 짧은 쓰기 방법입니다 x = x + y. 때문에 +=의 관점에서 정의 +하고 =당신이 경우에 문제를 만들 수 별도로 오버라이드 (override) 할 수 있도록 사업자 x += yx = x + y동일한 방식으로 행동하지 않았다.

하위 수준에서 C # 컴파일러는 두 표현식을 동일한 바이트 코드로 컴파일 할 가능성이 매우 높습니다. 즉, 프로그램 실행 중에 런타임에서 런타임에서 다르게 처리 할 수 없을 가능성이 높습니다 .

나는 당신이 그것을 별도의 연산처럼 취급하고 싶을 수도 있음을 이해할 수 있습니다 : x += 10당신 과 같은 진술에서 당신은 x객체를 변경하고 x + 10이전의 객체 위에 할당하기 전에 새로운 객체 생성하는 대신 시간 / 메모리를 절약 할 수 있다는 것을 알고 있습니다 .

그러나이 코드를 고려하십시오 :

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

a == b마지막에 해야합니까 ? 대부분의 유형에서 아니요 a는 10보다 큽니다 b. 그러나 +=연산자를 오버로드하여 변경을 할 수 있다면 가능합니다 . 이제을 고려 a하고 b프로그램의 먼 부분에 건네받을 수 있습니다. 코드가 예상하지 않은 곳에서 객체가 변경되기 시작하면 가능한 최적화로 인해 혼란스러운 버그가 발생할 수 있습니다.

다시 말해, 성능이 그렇게 중요한 경우 x += 10와 같은 메소드 호출 로 대체하기 어렵지 않으며 x.increaseBy(10)관련된 모든 사람에게 훨씬 명확합니다.


이는 할당 연산자가 오버로드 될 수없는 것과 같은 이유 때문입니다. 할당을 올바르게 수행하는 코드를 작성할 수 없습니다.

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.
   }
}

할당 연산자는 오버로드 될 수 없지만 + =는 +를 사용하여 평가되며, 오버로드 될 수 있습니다.

에서 MSDN .


이 연산자는 오버로드 될 수 없기 때문입니다.

할당 연산자는 오버로드 될 수 없지만 + =는 +를 사용하여 평가되며, 오버로드 될 수 있습니다.

MSDN

+때문에 과부하 연산자

x += y 동일 x = x + y


에 대한 연산자 과부하 ++=연산자에서 사용 A += B됩니다 A = operator+(A, B).


다음 +과 같이 연산자 를 과부하 하면 :

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

넌 할 수있어

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

또는

 foo = foo + 10;

컴파일과 똑같이 실행됩니다.


There is always the same answer to this problem: Why do you need the +=, if you get it for free if you overload the +. But what happens if I have a class like this.

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);
            }
        }
    }
}

Do you still say that it is good that the += is "auto-implemented". If you try to do high-performance computing in C# you need to have such features to reduce processing time and memory consumption, if someone has a good solution it is highly appreciated, but don't tell me I have to do this with static methods, this is only a workaround and I see no reason why C# does the += implemention if it is not defined, and if it is defined it will be used. Some people say that not having a difference between + and += prevents errors, but isn't this my own problem?


I had the exact same question and i can not possibly answer it better then this person has


A better design method is Explicit Casting. You can definitely overload Casting.

참고URL : https://stackoverflow.com/questions/6587107/c-sharp-operator-overload-for

반응형