2009-08-11 18 views
20

Có thực sự là không thể tạo ra một phương thức mở rộng trong C# trong đó thể hiện được chuyển thành tham chiếu không?Phương pháp mở rộng C# có cho phép truyền tham số bằng tham chiếu không?

Đây là một mẫu VB.NET console app:

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 

Lưu ý các tham số giá trị gia tăng được thông qua ByRef.

Và (gần như) cùng trong 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; 
    } 
    } 
} 

Các phương pháp khuyến nông Add không hoạt động trong C# vì tôi không thể sử dụng từ khóa ref. Có cách giải quyết nào cho vấn đề này không?

+0

Chỉ vì mục đích hoàn thành: giá trị chính xác để "Thêm" giá trị của enum cờ là 'Value = Value or Arg1' trừ khi bạn muốn thêm' Monday' hai lần hoạt động như thêm 'Tuesday'. Cách chính xác để xóa cờ là 'Giá trị = (Giá trị hoặc Arg1) Xor Arg1'. – LWChris

Trả lời

12

số Trong C#, bạn không thể chỉ định bất kỳ từ bổ nghĩa (như 'ra' hoặc ref) khác với this cho tham số đầu tiên của một phương pháp khuyến nông - bạn có thể cho những người khác. Không quen thuộc với Cú pháp VB nhưng dường như nó đang sử dụng cách tiếp cận khai báo để đánh dấu một phương thức mở rộng.

Khi bạn gọi điện thoại, bạn không chỉ định tham số this đầu tiên. Do đó đánh dấu tham số như hiện hoặc doesnt ref có ý nghĩa như Bạn không thể chỉ định sửa đổi khi bạn gọi nó như bạn muốn làm cho các phương pháp thông thường

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 

Tôi nghĩ rằng những rắc rối bạn gặp ở đây có liên quan đến các loại giá trị không thay đổi. Nếu các ngày trong tuần là một kiểu tham chiếu, nó sẽ hoạt động tốt. Đối với các kiểu không thay đổi (cấu trúc), cách defacto là trả về một cá thể mới với giá trị được yêu cầu. Ví dụ. Xem phương thức Thêm trên cấu trúc DateTime, nó trả về một cá thể DateTime mới có giá trị của giá trị của giá trị + giá trị của đối tượng DateTime của bộ nhận giá trị nhận.

public DateTime Add(TimeSpan value) 
+0

Trong vb, người ta có thể chỉ định rằng một phương thức mở rộng nhận hàm 'this' (' Me') ngụ ý như một tham số 'ByRef'; Thật không may, trình biên dịch sau đó tiến hành cho phép các cấu trúc chỉ đọc được truyền cho nó. Một trong những khiếu nại chính về các loại giá trị có thể thay đổi là vì không có gì để chỉ ra phương thức nào thay đổi 'this', chúng cho phép các phương thức như vậy được gọi là vô dụng trên các cá thể chỉ đọc. Tôi thấy kỳ lạ là những người thực thi vb.net sẽ quyết định cho phép một phương thức mở rộng có tham số 'ByRef' - thực tế la hét" Tôi S M MUTATE THE ARGUMENT! "- trong ngữ cảnh chỉ đọc. – supercat

11

Yikes - bạn đang tạo cấu trúc không thay đổi có thể thay đổi. Nó phá vỡ những gì mọi người mong đợi để thấy trong C#, nhưng nếu bạn phải, thì bạn luôn có thể gọi trực tiếp phương thức:

Ext.Add(ref value, arg1); 

Bất kỳ phương pháp khuyến khích nào cũng có thể gọi trực tiếp.

Ngoài ra, làm rõ:

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

cấu trúc bất biến có thể thay đổi? –

+1

yep, Eric Lippert sẽ thích điều đó;) –

+2

Enums là các giá trị không thay đổi, nhưng chuyển một giá trị bằng tham chiếu vì tham số này đến một phương thức mở rộng sẽ làm cho nó hoạt động giống như một giá trị có thể thay đổi. –

4

Lạ mà VB.NET cho phép này và C# không ...

Tuy nhiên, mặc dù nó có thể có ý nghĩa từ một quan điểm kỹ thuật (kể từ một phương thức mở rộng chỉ là một phương thức tĩnh), tôi nghĩ rằng nó không cảm thấy đúng, bởi vì các phương thức mở rộng được sử dụng như thể chúng là các phương thức mẫu và các phương thức mẫu không thể sửa đổi tham chiếu this.

+8

Trong thực tế các phương pháp ví dụ * có thể * sửa đổi "này" trong các loại giá trị. Lạ lùng nhưng đúng. –

+1

wow ... Tôi chưa bao giờ nhận ra điều đó! –

+3

Không cần phải nói rằng SUCKS này dành thời gian lớn cho C#. –