2011-01-11 9 views
23

¿Se pueden agregar métodos de extensión a una estructura?Métodos de extensión en una estructura

+7

¿Has intentado agregar un método de extensión en una estructura? Tenga en cuenta que no debe eliminar preguntas cuando encuentre la respuesta a ellas, otros podrían preguntarse sobre lo mismo. Y sí, puede declararlos, pero cambiar las cosas en la estructura no funcionará como espera, a menos que espere que no funcione. –

+1

Sí, lo intenté pero no funcionó. –

+1

Gracias funcionó, mi error –

Respuesta

18

Sí, puede agregar métodos de extensión en las estructuras. Según la definición del método de extensión, puede lograrlo fácilmente. A continuación se muestra un ejemplo del método de extensión en int

namespace ExtensionMethods 
{ 
    public static class IntExtensions 
    { 
     public static bool IsGreaterEqualThan(this int i, int value) 
     { 
      return i >= value; 
     } 
    } 
} 
+17

Sin embargo, tenga cuidado con esto, ya que la estructura se pasa al método de extensión POR VALOR (como se quiere hacer con las estructuras). Por lo tanto, cualquier modificación que haga a la estructura en el método de extensión se perderá, a menos que devuelva la estructura del curso (y luego haga algo con esa estructura pasada, como reasignarla a sí misma). No hay forma de hacer un método de extensión en una estructura y hacer que se pase por referencia (en C#). – BrainSlugs83

+0

Parece que no puedo extender System.Drawing.Rectangle que también es una estructura, y está decorado con Serializable y ComVisible y TypeConverter. – zionpi

17

Es posible agregar métodos de extensión a las estructuras, pero hay una advertencia importante. Los métodos de métodos de estructura normales aceptan this como un parámetro ref, pero C# no permitirá la definición de métodos de extensión que lo hagan. Si bien los métodos struct que cambian this pueden ser algo peligrosos (dado que el compilador permitirá que los métodos struct se invoquen en estructuras de solo lectura, pero pase this por valor), a veces también pueden ser útiles si se tiene cuidado de asegurarse de que sean solo se usa en contextos apropiados.

A propósito, vb.net permite que los métodos de extensión acepten this como un parámetro ByRef, ya sea una clase, estructura o un genérico de categoría desconocida. Esto puede ser útil en algunos casos donde las interfaces pueden ser implementadas por estructuras. Por ejemplo, si se intenta invocar en una variable del tipo List<string>.Enumerator un método de extensión que toma un parámetro this del tipo IEnumerator<string>, o toma por valor un parámetro this de un genérico restringido a IEnumerator<string>, y si el método intenta avanzar al enumerador, cualquier avance se deshará cuando regrese el método. Sin embargo, un método de extensión que toma un genérico restringido por referencia (posible en vb.net) se comportará como debería.

+1

Entonces, ¿qué podría ser un ejemplo de usar uno en C#? 'public static Rect CreateRectFromPercents (this Rect rect)' por ejemplo no funciona. – MichaelTaylor3D

+0

@ MichaelTaylor3D: ¿Qué es 'Rect'? ¿Quiere decir 'System.Drawing.Rectangle' o algún tipo personalizado? – supercat

+0

es una estructura que es parte de mi uso de API. Solo lo estaba usando como un ejemplo. La API me impide modificarla directamente, así que esperaba usar un método de extensión. He leído que es posible para las estructuras pero aún no he visto un ejemplo. Tu explicación es lo más cercano que puedo encontrar. – MichaelTaylor3D

2

Sí, puede definir un método de extensión en un tipo de estructura/valor. Sin embargo, no tienen el mismo comportamiento que los métodos de extensión en los tipos de referencia.

Por ejemplo, el método de extensión GetA() en el siguiente código C# recibe una copia de la estructura, no una referencia a la estructura. Esto significa que un método de extensión C# en una estructura no puede modificar el contenido original de la estructura.

public static class TestStructExtensionMethods { 
    public struct FooStruct { 
     public int a; 
    } 
    public static int GetA(this FooStruct st) { 
     return st.a; 
    } 
} 

Para modificar el contenido de la estructura, el struct paramater debe declararse como "ref". Sin embargo, "esta referencia" no está permitida en C#. Lo mejor que podemos hacer es un método no estático como extensión:

// this works, but is inefficient, because it copies the whole FooStruct 
// just to return a 
public static int GetA(ref FooStruct st) { 
    return st.a; 
} 

En VB.NET, puede crear esto como un método de extensión ByRef estructura, por lo que podría modificar la estructura original de:

' This is efficient, because it is handed a reference to the struct 
<Extension()> _ 
Public Sub GetA(ByRef [me] As FooStruct) As Integer 
    Return [me].a 
End Sub 

' It is possible to change the struct fields, because we have a ref 
<Extension()> _ 
Public Sub SetA(ByRef [me] As FooStruct, newval As Integer) 
    [me].a = newval 
End Sub 
+0

Ese VB.NET permite que los métodos de extensión acepten estructuras por 'ref' sería una buena cosa, pero por el hecho de que VB copiará silenciosamente cosas que' ref' no pueden pasar y pasará las copias en lugar de los originales. Si hubiera una manera de decirle a VB.NET que no hiciera eso (el código debería en cambio negarse a compilar), dichos métodos de extensión serían semánticamente superiores a los métodos de instancias struct que modifican 'this'. No sé por qué MS no proporciona ningún medio por el cual los métodos puedan indicar si deberían ser invocables en las estructuras temporales generadas por el compilador. – supercat

+0

"... pero por el hecho de que VB copiará silenciosamente cosas que no pueden pasarse por ref y pasará las copias en lugar de los originales" - ¿cuándo lo hace VB? - "byref" se compila con el mismo código IL que "ref" en C# - mi entendimiento es que cualquier cosa puede pasar por ref en .NET - las únicas cosas que se copian son los tipos de valor (y solo cuando ellos no son aprobados por ref). – BrainSlugs83

+0

@ BrainSlugs83: Intente pasar una propiedad de lectura/escritura por referencia en VB.net. Esa propiedad es simplemente el valor de retorno de la función getter, no una variable ... por lo que pasar por referencia no funciona. C# no lo permitirá. En lugar de eso, VB modificará el paso por referencia copiando el valor y pasando la * copia * por referencia ... luego, cuando la función vuelva, establecerá la propiedad en el nuevo valor. Lo cual * en su mayoría * funciona, y mantiene las propiedades translúcidas, si sigue LoD y mantiene las estructuras inmutables ... pero puede romperse de maneras semi-sorprendentes cuando los sub-objetos y los tipos de valores mutables se involucran. – cHao

5

Para futuros Googlers (y Bingers), aquí hay un código para extender una estructura. Este ejemplo convierte el valor en un tipo double.

public static class ExtensionMethods { 

    public static double ToDouble<T>(this T value) where T : struct { 
     return Convert.ToDouble(value); 
    } 
} 

Después de ello se puede utilizar como ToDouble() utiliza ToString(). Tenga cuidado con los elementos de conversión como desbordamientos.

Cuestiones relacionadas