C#扩展方法是否允许通过引用传递参数?

是否真的不可能在C#中创建一个扩展方法,其中实例作为引用传递?

这是一个示例VB.NET控制台应用程序:

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  _ Public Enum Weekdays Monday = 1 Tuesday = 2 Wednesday = 4 Thursday = 8 Friday = 16 Saturday = 32 Sunday = 64 End Enum Module Ext  _ Public Sub Add(ByRef Value As Weekdays, ByVal Arg1 As Weekdays) Value = Value + Arg1 End Sub End Module 

请注意,Value参数是ByRef传递的。

和(几乎)在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; } } } 

Add扩展方法在C#中不起作用,因为我无法使用ref关键字。 这有什么解决方法吗?

在C#中,您不能为扩展方法的第一个参数指定除此之外的任何修饰符(如“out”或ref ) – 您可以为其他参数指定。 不熟悉VB语法,但它似乎使用声明方法来标记扩展方法。

调用它时, 指定第一个this参数。 因此将参数标记为out或ref没有意义,因为您在调用它时无法像通常的方法那样指定修饰符

 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 

我认为你在这里遇到的麻烦与价值类型是不可变的有关。 如果工作日是一个参考类型,它会好起来的。 对于不可变类型(结构),事实上的方法是返回具有所需值的新实例。 例如,请参阅结构DateTime上的Add方法,它返回一个新的DateTime实例,其值= receiver DateTime实例的值+ param值。

 public DateTime Add( TimeSpan value ) 

哎呀 – 你正在制作一个可变的不可变结构。 它打破了人们期望在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); 

奇怪的是,VB.NET允许这个而C#不…

但是,虽然从技术角度来看它可能有意义(因为扩展方法只是一个静态方法),我觉得它感觉不对,因为扩展方法就好像它们是实例方法一样,而实例方法可以不要修改this引用。