tipos - ¿Los métodos de extensión C#no permiten pasar parámetros por referencia?
pasar tipo como parametro c# (3)
Es extraño que VB.NET lo permita y C # no ...
Sin embargo, aunque podría tener sentido desde un punto de vista técnico (dado que un método de extensión es solo un método estático), creo que no se siente bien, porque los métodos de extensión se usan como si fueran métodos de instancia, y los métodos de instancia pueden no modifique this
referencia.
¿Es realmente imposible crear un método de extensión en C # donde la instancia se pasa como referencia?
Aquí hay una aplicación de consola de ejemplo de 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
Tenga en cuenta que el parámetro Value se pasa por RefRef.
Y (casi) lo mismo en 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;
}
}
}
El método Add
extensión no funciona en C # porque no puedo usar la palabra clave ref
. ¿Hay alguna solución para esto?
No. En C #, no puede especificar ningún modificador (como ''out'' o ref
) que no sea para el primer parámetro de un método de extensión; puede hacerlo para los demás. No está familiarizado con la sintaxis de VB, pero parece estar usando un enfoque declarativo para marcar un método de extensión.
Cuando lo llamas, no especificas el primero this
parámetro. Por lo tanto, marcar el parámetro como out o ref no tiene sentido ya que no se puede especificar el modificador cuando se lo llame como lo haría con los métodos normales
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
Creo que el problema que tienes aquí está relacionado con los tipos de valores que son inmutables. Si Weekdays fue un tipo de referencia, funcionaría bien. Para tipos inmutables (estructuras), la forma defacto es devolver una nueva instancia con el valor requerido. Por ejemplo, vea el método Add en la estructura DateTime, devuelve una nueva instancia de DateTime cuyo valor = valor de param + valor de la instancia de DateTime del receptor.
public DateTime Add( TimeSpan value )
Yikes: estás haciendo una estructura mutable e inmutable. Rompe lo que la gente espera ver en C #, pero si debe, entonces siempre puede llamar directamente al método:
Ext.Add(ref value, arg1);
Cualquier método de extensión es directamente invocable.
Además, una aclaración:
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);