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

发布于 2024-08-01 23:45:51 字数 1755 浏览 6 评论 0原文

在 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

<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

请注意,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 关键字。 有什么解决方法吗?

Is it really impossible to create an extension method in C# where the instance is passed as a reference?

Here’s a sample 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

Note the Value parameter is passed ByRef.

And (almost) the same in 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. Is there any workaround for this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

千紇 2024-08-08 23:45:51

不可以。在 C# 中,您不能为扩展方法的第一个参数指定除 this 之外的任何修饰符(例如“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

我认为您在这里遇到的麻烦与不可变的值类型有关。 如果 Weekdays 是一个参考类型,那就没问题了。 对于不可变类型(结构),事实上的方法是返回具有所需值的新实例。 例如,参见 struct DateTime 上的 Add 方法,它返回一个新的 DateTime 实例,其值 = 接收者 DateTime 实例的值 + 参数值。

public DateTime Add( TimeSpan value )

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. Not familiar with the VB Syntax but it seems to be using a declarative approach to mark an extension method.

When you call it, you do not specify the first this parameter. 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

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. E.g. See the Add method on the struct DateTime, it returns a new DateTime instance whose value = receiver DateTime instance's value + param value.

public DateTime Add( TimeSpan value )
记忆で 2024-08-08 23:45:51

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

Yikes - you're making a mutable immutable struct. It breaks what people expect to see in C#, but if you must, then you can always directly call the method:

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);
旧夏天 2024-08-08 23:45:51

奇怪的是 VB.NET 允许这样做,而 C# 不允许...

但是,虽然从技术角度来看这可能有意义(因为扩展方法只是一个静态方法),但我认为这感觉不对,因为扩展方法的使用就像实例方法一样,并且实例方法不能修改 this 引用。

Strange that VB.NET allows this and C# doesn't...

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文