简体   繁体   English

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

[英]Doesn't C# Extension Methods allow passing parameters by reference?

Is it really impossible to create an extension method in C# where the instance is passed as a reference? 真的不可能在将实例作为引用传递的C#中创建扩展方法吗?

Here's a sample VB.NET console app: 这是一个示例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

<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

Note the Value parameter is passed ByRef. 注意Value参数是通过ByRef传递的。

And (almost) the same in C#: 并且(几乎)在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;
    }
  }
}

The Add extension method doesn't work in C# because I can't use the ref keyword. Add扩展方法在C#中不起作用,因为我不能使用ref关键字。 Is there any workaround for this? 有什么解决方法吗?

No. In C#, you cannot specify any modifiers (like 'out' or ref ) other than this for the first parameter of an extension method - you can for the others. 号在C#,则不能指定任何改性剂(如“出”或ref )比其它this用于扩展方法的第一个参数-你可以为其他人。 Not familiar with the VB Syntax but it seems to be using a declarative approach to mark an extension method. 虽然不熟悉VB语法,但似乎正在使用声明性方法来标记扩展方法。

When you call it, you do not specify the first this parameter. 调用它时,您无需指定第一个this参数。 Hence marking the parameter as out or ref doesnt make sense as You can't specify the modifier when you call it like you'd do for normal methods 因此,将参数标记为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

I think the trouble you're having here is related to value types being immutable. 我认为您在这里遇到的麻烦与值类型不可变有关。 If Weekdays was a reference type, it would work out alright. 如果“工作日”是一种参考类型,则可以正常工作。 For immutable types (structs), the defacto way is to return a new instance with the required value. 对于不可变类型(结构),事实上的方法是返回具有所需值的新实例。 Eg See the Add method on the struct DateTime, it returns a new DateTime instance whose value = receiver DateTime instance's value + param value. 例如,参见结构DateTime上的Add方法,它将返回一个新的DateTime实例,其值=接收者DateTime实例的值+参数值。

public DateTime Add( TimeSpan value )

Yikes - you're making a mutable immutable struct. Yikes-您正在构建一个可变的不可变结构。 It breaks what people expect to see in C#, but if you must, then you can always directly call the method: 它破坏了人们期望在C#中看到的内容,但是如果必须这样做,则始终可以直接调用该方法:

Ext.Add(ref value, arg1);

Any extension method is directly callable. 任何扩展方法都可以直接调用。

Also, a clarification: 另外,澄清:

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

Strange that VB.NET allows this and C# doesn't... 奇怪的是VB.NET允许这样做,而C#却不允许...

However, although it might make sense from a technical point of view (since an extension method is just a static method), I think it doesn't feel right, because extension methods are used as if they were instance methods, and instance methods can't modify the this reference. 但是,尽管从技术角度来看这可能是有道理的(因为扩展方法只是静态方法),但我认为这样做不合适,因为扩展方法的使用就好像它们是实例方法一样,而实例方法可以请勿修改this参考。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM