2009-08-11 4 views
20

인스턴스가 참조로 전달되는 C#에서 확장 메서드를 만드는 것은 정말로 불가능합니까? 값 매개 변수가하는 ByRef 전달됩니다C# 확장 메서드에서 참조로 매개 변수를 전달할 수 있습니까?

Imports System.Runtime.CompilerServices 

Module Module1 
    Sub Main() 
    Dim workDays As Weekdays 

    workDays.Add(Weekdays.Monday) 
    workDays.Add(Weekdays.Tuesday) 

    Console.WriteLine("Tuesday is a workday: {0}", _ 
     CBool(workDays And Weekdays.Tuesday)) 
    Console.ReadKey() 
    End Sub 
End Module 

<Flags()> _ 
Public Enum Weekdays 
    Monday = 1 
    Tuesday = 2 
    Wednesday = 4 
    Thursday = 8 
    Friday = 16 
    Saturday = 32 
    Sunday = 64 
End Enum 

Module Ext 
    <Extension()> _ 
    Public Sub Add(ByRef Value As Weekdays, ByVal Arg1 As Weekdays) 
    Value = Value + Arg1 
    End Sub 
End Module 

참고 :

다음은 샘플 VB.NET 콘솔 응용 프로그램입니다.

그리고 (거의) C#에서 같은 :

using System; 

namespace CS.Temp 
{ 
    class Program 
    { 
    public static void Main() 
    { 
     Weekdays workDays = 0; 

     workDays.Add(Weekdays.Monday); // This won't work 
     workDays.Add(Weekdays.Tuesday); 

     // You have to use this syntax instead... 
     // workDays = workDays | Weekdays.Monday; 
     // workDays = workDays | Weekdays.Tuesday; 

     Console.WriteLine("Tuesday is a workday: {0}", _ 
     System.Convert.ToBoolean(workDays & Weekdays.Tuesday)); 
     Console.ReadKey(); 
    } 
    } 

    [Flags()] 
    public enum Weekdays : int 
    { 
    Monday = 1, 
    Tuesday = 2, 
    Wednesday = 4, 
    Thursday = 8, 
    Friday = 16, 
    Saturday = 32, 
    Sunday = 64 
    } 

    public static class Ext 
    { 
    // Value cannot be passed by reference? 
    public static void Add(this Weekdays Value, Weekdays Arg1) 
    { 
     Value = Value | Arg1; 
    } 
    } 
} 

나는 ref 키워드를 사용할 수 없기 때문에 Add 확장 메서드는 C#으로 작동하지 않습니다. 이 문제를 해결할 수있는 방법이 있습니까?

+0

그냥 완성을 위하여 : 당신은'Monday' 두 번 추가하는'Tuesday'를 추가처럼 동작 것을 원하지 않는다면 플래그 열거 형의 값을 "추가"하는 올바른 방법 '값 = 값 또는 Arg1'입니다. 플래그를 제거하는 올바른 방법은'Value = (Value 또는 Arg1) Xor Arg1'입니다. – LWChris

답변

12

번호, 당신은 은 확장 메서드의 첫 번째 매개 변수에 대한 this 이외의 ('아웃'또는 ref 같은) 어떤 수식을 지정할 수 없습니다. VB 구문에 익숙하지 않지만 선언 방법을 사용하여 확장 메서드를 표시하는 것으로 보입니다.

은 첫 번째 매개 변수를 지정하지 않습니다. 따라서 같은 출력 매개 변수를 표시 또는 당신은 당신이 여기에서 발생하는 문제가 관련이

void MyInstanceMethod(ref SomeClass c, int data) { ... } // definition 

obj.MyInstanceMethod(ref someClassObj, 10);    // call 

void MyExtensionMethod(this SomeClass c, int data) {.... } // defn 

c.MyExtensionMethod(10);         // call 

내가 생각하는 일반적인 방법

을 위해 할 것 같은 당신이 그것을 호출 할 때 수정을 지정할 수 없습니다로 심판 나던 이해 값 유형을 변경할 수 없습니다. 평일을 참조 유형이라면 괜찮습니다. 변경 불가능한 타입 (structs)의 경우, 필수적인 값을 가진 새로운 인스턴스를 반환하는 것이 가장 좋은 방법입니다. 예 : struct DateTime의 Add 메서드를 보면 값이 receiverTimeTime 인스턴스의 value + param 값인 새 DateTime 인스턴스가 반환됩니다.

public DateTime Add(TimeSpan value) 
+0

vb에서는, 확장 메소드가 묵시적'this' ('Me')를'ByRef' 파라미터로서 취하도록 지정할 수 있습니다; 불행히도 컴파일러는 읽기 전용 구조가 전달되도록 허용합니다. 가변 값 유형에 대한 주요 불만 중 하나는 어떤 메소드가 'this'를 변경한다는 것을 나타내는 것이 없으므로 읽기 전용 인스턴스에서 이러한 메소드를 쓸데없이 호출 할 수 있다는 것입니다. vb.net 구현자가 'ByRef' 매개 변수를 사용하는 확장 메서드를 허용하도록 결정하는 것이 이상하게 느껴집니다. 실제로는 "내가 인수를 무효화 할 것입니다!"- 읽기 전용 컨텍스트에서. – supercat

11

Yikes - 변경할 수없는 구조체를 만들고 있습니다. 그것은 사람들이 C#으로 볼 것으로 예상 무엇을 중단하지만, 당신이해야하는 경우에, 당신은 항상 직접 메서드를 호출 할 수 있습니다

Ext.Add(ref value, arg1); 

모든 확장 메서드를 직접 호출입니다. 이 때문에 (기술적 관점에서 이해 수도 있지만

SomeReferenceType value = ...; 
SomeReferenceType copy = value; 
value.ExtensionMethodByRef(...); 
// this failing is semantically ridiculous for reference types, which 
// is why it makes no sense to pass a `this` parameter by ref. 
object.ReferenceEquals(value, copy); 
+4

변경할 수없는 구조체? –

+1

예, Eric Lippert가 좋아할 것입니다.) –

+2

열거 형은 변경할 수없는 값이지만이 매개 변수로 참조로 전달하여 확장 메서드에 전달하면 변경 가능한 값처럼 동작합니다. –

4

이상한 VB.NET이 할 수 있고 C#을하지 않는 ... 그러나

: 또한

, 해명 확장 메서드는 정적 메서드 일뿐입니다.) 확장 메서드는 인스턴스 메서드 인 것처럼 사용되며 인스턴스 메서드는 this 참조를 수정할 수 없기 때문에 적절하지 않다고 생각합니다. 당신이 할 수있는 다른 사람을위한 - C#에서

+8

사실 인스턴스 메소드 *는 값 유형에서 "this"를 수정할 수 있습니다. 이상하지만 진실. –

+1

와우 ... 나는 그것을 결코 깨닫지 못했다! –

+3

이 SUCKS는 C#의 큰 시간입니다. –

관련 문제