C # 확장 메서드를 사용하여 연산자 오버로드


174

확장 메서드를 사용하여 C # StringBuilder클래스에 연산자 오버로드를 추가하려고합니다 . 특히, 주어진 StringBuilder sb, 내가 좋아하는 것 sb += "text"에 해당되기 위해 sb.Append("text").

다음에 대한 확장 메소드를 작성하는 구문은 다음과 같습니다 StringBuilder.

public static class sbExtensions
{
    public static StringBuilder blah(this StringBuilder sb)
    {
        return sb;
    }
} 

blah확장 방법을에 성공적으로 추가 합니다 StringBuilder.

불행히도 연산자 오버로드는 작동하지 않는 것 같습니다.

public static class sbExtensions
{
    public static StringBuilder operator +(this StringBuilder sb, string s)
    {
        return sb.Append(s);
    }
} 

다른 문제 중에서도 키워드 this는이 문맥에서 허용되지 않습니다.

확장 방법을 통해 연산자 과부하를 추가 할 수 있습니까? 그렇다면 적절한 방법은 무엇입니까?


4
처음에는 이것이 멋진 아이디어처럼 보이지만 var otherSb = sb + "hi";
도끼-SOverflow로 완료

답변:


150

확장 메서드는 정적 클래스에 있어야하며 정적 클래스에는 연산자 오버로드를 가질 수 없으므로 현재는 불가능합니다.

C # Language PM의 Mads Torgersen은 다음과 같이 말합니다.

Orcas 릴리스의 경우 익스텐션 속성, 이벤트, 연산자, 정적 메소드 등과 달리 신중한 접근 방식을 사용하고 정규 확장 메소드 만 추가하기로 결정했습니다. 정규 확장 메소드는 LINQ에 필요한 것입니다. 다른 멤버들에게는 쉽게 흉내낼 수없는 문법적으로 최소한의 디자인.

우리는 다른 종류의 확장 멤버가 유용 할 수 있음을 점점 더 인식하고 있으므로 Orcas 이후에이 문제로 돌아갈 것입니다. 그러나 보장은 없습니다!

편집하다:

방금 Mads가 같은 기사 에서 더 많은 것을 썼습니다 .

다음 릴리스에서는이 작업을 수행하지 않을 것입니다. 우리는 확장 멤버를 우리 계획에서 매우 진지하게 받아 들였고, 제대로하려고 노력하기 위해 많은 노력을 기울 였지만 결국 우리는 충분히 매끄럽지 못하고 다른 흥미로운 기능을 제공하기로 결정했습니다.

이것은 향후 출시를 위해 여전히 우리의 레이더에 있습니다. 올바른 디자인을 이끌어내는 데 도움이되는 많은 양의 매력적인 시나리오를 얻는다면 도움이 될 것입니다.


이 기능은 현재 C # 8.0의 테이블에 있습니다 (잠재적으로). Mads는 여기서 그것을 구현하는 것에 대해 조금 더 이야기합니다 .


이 페이지는 이후 게시 중단되었습니다. 이 문제는 여전히 해결되지 않았습니다.
Chris Moschini 2014

17
너무 나쁘다. 방금 TimeSpan에 스칼라 값을 곱하는 연산자를 추가하고 싶었습니다 ... :(
Filip Skakun

StringPowerShell 에 캐스팅하기 위해 동일한 개념을 구현하기를 바랐습니다 ScriptBlock.
Trevor Sullivan

즉, %를 부울 x 또는 초과하지 않을 수 있습니까? :( true.Xor(false)당시 사망
SparK

3
@SparK ^는 C #의 xor 연산자입니다.
Jacob Krall

57

이 "확장 연산자"(일반적으로 확장 방법으로 수행)를 사용하려는 위치를 제어하는 ​​경우 다음과 같이 할 수 있습니다.

class Program {

  static void Main(string[] args) {
    StringBuilder sb = new StringBuilder();
    ReceiveImportantMessage(sb);
    Console.WriteLine(sb.ToString());
  }

  // the important thing is to use StringBuilderWrapper!
  private static void ReceiveImportantMessage(StringBuilderWrapper sb) {
    sb += "Hello World!";
  }

}

public class StringBuilderWrapper {

  public StringBuilderWrapper(StringBuilder sb) { StringBuilder = sb; }
  public StringBuilder StringBuilder { get; private set; }

  public static implicit operator StringBuilderWrapper(StringBuilder sb) {
    return new StringBuilderWrapper(sb);
  }

  public static StringBuilderWrapper operator +(StringBuilderWrapper sbw, string s) { 
      sbw.StringBuilder.Append(s);
      return sbw;
  }

} 

StringBuilderWrapper클래스가 선언 암시 적 변환 연산자 (A)로부터 StringBuilder 그리고 원하는 선언 +오퍼레이터. 이런 식으로 a StringBuilder가로 전달 될 수 있으며 ,이 연산자는 ReceiveImportantMessage자동으로로 변환되어 연산자를 사용할 수 있습니다.StringBuilderWrapper+

호출자에게보다 투명이 사실, 당신은 선언 할 수 있도록하기 위해 ReceiveImportantMessage복용하는으로 StringBuilder같은 단지 코드를 사용 :

  private static void ReceiveImportantMessage(StringBuilder sb) {
    StringBuilderWrapper sbw = sb;
    sbw += "Hello World!";
  }

또는 이미를 사용하는 곳에서 인라인으로 사용하려면 StringBuilder다음과 같이하면됩니다.

 StringBuilder sb = new StringBuilder();
 StringBuilderWrapper sbw = sb;
 sbw += "Hello World!";
 Console.WriteLine(sb.ToString());

더 이해 하기 쉽도록 비슷한 접근법을 사용하는 것에 대한 게시물을 작성 했습니다IComparable .


2
@ 레온 : 나는 그것을 상속하지 않고 작성하려고했습니다. 어쨌든 봉인되어 상속받지 못했습니다.
Jordão

5
@Leon : 이것이이 기술의 핵심입니다. 나는 거기 때문에 그렇게 할 수있는 암시 적 변환 연산자 에 선언 StringBuilderWrapper그 것을 가능하게한다.
Jordão

1
@ pylover : 맞습니다. 새 유형을 만들어야합니다.이 유형은 StringBuilder유형 을 감싸고 암시 적 변환 연산자를 제공합니다. 그 후, 예제에서 보여지는 것처럼 문자열 리터럴과 함께 사용될 있습니다 :sb += "Hello World!";
Jordão

2
그런 다음 확장 메소드를 추가하는 것이 좋습니다 String. PushIndent(" ".X(4))(라고도 함 Times). 또는이 생성자를 사용하십시오 : PushIndent(new String(' ', 4)).
Jordão

1
@ 조 르당 : 좋은 답변;)
비니키우스

8

현재 불가능한 것 같습니다. Microsoft Connect에서이 기능을 요청하는 공개 피드백 문제가 있습니다.

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=168224

향후 릴리스에 표시 될 수 있지만 현재 버전에는 구현되지 않았 음을 제안합니다.


"현재 불가능"이란 정확히 무엇을 의미합니까? F #은 확장을 모두 지원하기 때문에 CLR에서 가능해야합니다.
Matthew Olenik

1
그는 CLR이 아니라 C #에서는 불가능하다는 것을 의미한다고 생각합니다. 어쨌든 전체 확장 방법은 C # 컴파일러 트릭입니다.
tofi9

1
링크가 죽었습니다.
CBHacking

1

연산자를 수행 할 수는 없지만 항상 추가 (또는 Concat), 빼기 및 비교 메소드를 작성할 수 있습니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;    

namespace Whatever.Test
{
    public static class Extensions
    {
        public static int Compare(this MyObject t1, MyObject t2)
        {
            if(t1.SomeValueField < t2.SomeValueField )
                return -1;
            else if (t1.SomeValueField > t2.SomeValueField )
            {
                return 1;
            }
            else
            {
                return 0;
            }
        }

        public static MyObject Add(this MyObject t1, MyObject t2)
        {
            var newObject = new MyObject();
            //do something  
            return newObject;

        }

        public static MyObject Subtract(this MyObject t1, MyObject t2)
        {
            var newObject= new MyObject();
            //do something
            return newObject;    
        }
    }


}

1

하! sb + = (thing)에 대해 정확히 동일한 욕구를 가진 "확장 연산자 오버로드"를 찾고있었습니다.

여기에 대한 답변을 읽은 후 (그리고 대답이 "아니오"라는 것을 알면) 내 필요에 따라 sb.AppendLine과 sb.AppendFormat을 결합하는 확장 방법을 사용하여 어느 것보다 깔끔하게 보입니다.

public static class SomeExtensions
{
    public static void Line(this StringBuilder sb, string format, params object[] args)
    {
        string s = String.Format(format + "\n", args);
        sb.Append(s);
    }

}

그래서

sb.Line("the first thing is {0}",first);
sb.Line("the second thing is {0}", second);

일반적인 대답은 아니지만, 이런 종류의 것을보고있는 미래의 구직자들에게는 관심이있을 수 있습니다.


4
확장 방법을 AppendLine대신 이름을 지정하면 더 잘 읽을 수 있다고 생각합니다 Line.
DavidRR

0

래퍼와 확장 프로그램으로 조작 할 수는 있지만 제대로 수행 할 수는 없습니다. 당신은 목적을 완전히 물리 치는 쓰레기로 끝납니다. 여기 어딘가에 게시물이 있지만 그 가치가 없습니다.

Btw 모든 숫자 변환은 수정해야하는 문자열 빌더에서 가비지를 작성합니다. 작동하는 래퍼를 작성하여 사용했습니다. 그것은 가치가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.