Разве методы расширения 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

<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 ключевое слово. Есть ли обходной путь для этого?

3 ответов


нет. В C#не может укажите любые модификаторы (например, " out " или ref), кроме this для первого параметра метода расширения - вы можете для других. не знаком с синтаксисом VB, но, похоже, использует декларативный подход для обозначения метода расширения.

когда вы называете его, вы не Укажите первый


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

странно, что VB.NET позволяет это, а C# - нет...

однако, хотя это может иметь смысл с технической точки зрения (поскольку метод расширения-это просто статический метод), я думаю, что это неправильно, потому что методы расширения используются так, как если бы они были методами экземпляра, а методы экземпляра не могут изменить this ссылка.