una sobreescritos polimorfico método metodos metodo llamar genérica funciones extensión estática ejemplo definirse debe clases clase and c# linq extension-methods initializer

sobreescritos - ¿Hay alguna forma de utilizar un método de extensión en un bloque de inicializador de objetos en C#



un método de extensión debe definirse en una clase estática no genérica (6)

La demostración simple a continuación captura lo que intento hacer. En el programa real, tengo que usar el bloque de inicializador de objeto ya que está leyendo una lista en una expresión de selección LINQ a SQl, y hay un valor que quiero leer de la base de datos y almacenar en el objeto, pero el objeto no tiene una propiedad simple que pueda establecer para ese valor. En cambio, tiene un almacén de datos XML.

Parece que no puedo llamar a un método de extensión en el bloque de inicializador de objetos, y que no puedo adjuntar una propiedad utilizando métodos de extensión.

Entonces, ¿no tengo suerte con este enfoque? La única alternativa parece ser persuadir al propietario de la clase base para que la modifique para este escenario.

Tengo una solución existente en la que subclase BaseDataObject, pero esto también tiene problemas que no aparecen en este ejemplo simple. Los objetos se conservan y restauran como BaseDataObject: los moldes y las pruebas se volverán complejos.

public class BaseDataObject { // internal data store private Dictionary<string, object> attachedData = new Dictionary<string, object>(); public void SetData(string key, object value) { attachedData[key] = value; } public object GetData(string key) { return attachedData[key]; } public int SomeValue { get; set; } public int SomeOtherValue { get; set; } } public static class Extensions { public static void SetBarValue(this BaseDataObject dataObject, int barValue) { /// Cannot attach a property to BaseDataObject? dataObject.SetData("bar", barValue); } } public class TestDemo { public void CreateTest() { // this works BaseDataObject test1 = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 }; // this does not work - it does not compile // cannot use extension method in the initialiser block // cannot make an exension property BaseDataObject test2 = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4, SetBarValue(5) }; } }

Una de las respuestas (de mattlant) sugiere usar un método de extensión de estilo de interfaz fluido. p.ej:

// fluent interface style public static BaseDataObject SetBarValueWithReturn( this BaseDataObject dataObject, int barValue) { dataObject.SetData("bar", barValue); return dataObject; } // this works BaseDataObject test3 = (new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 }).SetBarValueWithReturn(5);

Pero, ¿funcionará esto en una consulta LINQ?


¿Está extendiendo la clase una posibilidad? Entonces podría agregar fácilmente la propiedad que necesita.

De lo contrario, puede crear una clase nueva que tenga propiedades similares que simplemente devuelva la llamada a una instancia privada de la clase que le interese.


Los Inicializadores de objetos son solo azúcares sintácticos que requieren un compilador inteligente y, a partir de la implementación actual, no se pueden invocar métodos en el inicializador.

var x = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 };

Hará que el compilador tenga algo como esto:

BaseDataObject tempObject = new BaseDataObject(); tempObject.SomeValue = 3; tempObject.SomeOtherValue = 4; BaseDataObject x = tempObject;

La diferencia es que no puede haber problemas de sincronización. La variable x get tiene asignado el objeto BaseDataObject completamente asignado a la vez, no se puede meter con el objeto durante su inicialización.

Simplemente puede llamar al método de extensión después de la creación del objeto:

var x = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 }; x.SetBarValue()

Puede cambiar SetBarValue para que sea una propiedad con get / set que se puede asignar durante la inicialización:

public int BarValue { set { //Value should be ignored } }

O bien, puede crear una subclase / usar el patrón de fachada para agregar el método a su objeto:

public class DataObjectWithBarValue : BaseDataObject { public void BarValue { set { SetData("bar", value); } get { (int) GetData("bar"); } } }


No, pero podrías hacer esto ...:

BaseDataObject test2 = (new BaseDataObject { SomeValue = 3, SomeOtherValue = 4}).SetBarValue(5);

Y haz que tu extensión devuelva el objeto como lo hace Linq.

EDITAR: Esta fue una buena idea hasta que releí y vi que la clase base fue desarrollada por una tercera persona: también conocido como no tienes el código. Otros aquí han publicado una solución correcta.


static T WithBarValue<T>(this T dataObject, int barValue) where T : BaseDataObject { dataObject.SetData("bar", barValue); return dataObject; } var x = new BaseDataObject{SomeValue=3, OtherValue=4}.WithBarValue(5);


Aun mejor:

public static T SetBarValue<T>(this T dataObject, int barValue) where T : BaseDataObject { dataObject.SetData("bar", barValue); return dataObject; }

y puede usar este método de extensión para los tipos derivados de BaseDataObject para encadenar métodos sin moldes y preservar el tipo real cuando se deduce en un campo var o en un tipo anónimo.


Justo, después de haber aprendido de los contestadores, la breve respuesta a "¿Hay alguna forma de utilizar un método de extensión en un bloque de inicializador de objetos en C #?" es " No "

La forma en que eventualmente resolví el problema al que me enfrenté (similar, pero más complejo que el problema del juguete que planteé aquí) fue un enfoque híbrido, de la siguiente manera:

Creé una subclase, por ejemplo

public class SubClassedDataObject : BaseDataObject { public int Bar { get { return (int)GetData("bar"); } set { SetData("bar", value); } } }

Lo cual funciona bien en LINQ, el bloque de inicialización se ve como

SubClassedDataObject testSub = new SubClassedDataObject { SomeValue = 3, SomeOtherValue = 4, Bar = 5 };

Pero la razón por la que no me gustó este enfoque en primer lugar es que estos objetos se colocan en XML y vuelven a aparecer como BaseDataObject, y devolverlos iba a ser una molestia, una copia de datos innecesaria, y pondría dos copias del mismo objeto en juego.

En el resto del código, ignoré las subclases y usé los métodos de extensión:

public static void SetBar(this BaseDataObject dataObject, int barValue) { dataObject.SetData("bar", barValue); } public static int GetBar(this BaseDataObject dataObject) { return (int)dataObject.GetData("bar"); }

Y funciona bien