usan una que puede programacion las interfaz interfaces instancia implementacion heredar declaracion declara cómo crear como clase atributos c# compiler-construction anonymous-types

una - Solicitud de función C#: implementar interfaces en tipos anónimos



que es una interfaz en programacion (10)

Esto no sería posible actualmente.

¿Cuál sería la diferencia entre esto y simplemente hacer de IFoo una clase concreta en su lugar? Parece que esa podría ser la mejor opción.

¿Qué tomaría? Un nuevo compilador y toneladas de cheques para garantizar que no rompan las otras características. Personalmente, creo que sería más fácil exigir a los desarrolladores que simplemente creen una versión concreta de su clase.

Me pregunto qué se necesitaría para hacer algo como esto:

using System; class Program { static void Main() { var f = new IFoo { Foo = "foo", Print = () => Console.WriteLine(Foo) }; } } interface IFoo { String Foo { get; set; } void Print(); }

El tipo anónimo creado se vería así:

internal sealed class <>f__AnonymousType0<<Foo>j__TPar> : IFoo { readonly <Foo>j__TPar <Foo>i__Field; public <>f__AnonymousType0(<Foo>j__TPar Foo) { this.<Foo>i__Field = Foo; } public <Foo>j__TPar Foo { get { return this.<Foo>i__Field; } } public void Print() { Console.WriteLine(this.Foo); } }

¿Hay alguna razón por la cual el compilador no podría hacer algo como esto? Incluso para métodos no válidos o métodos que toman parámetros, el compilador debería poder inferir los tipos de la declaración de interfaz.

Descargo de responsabilidad: Si bien me doy cuenta de que esto no es posible actualmente y que tendría más sentido simplemente crear una clase concreta en este caso, estoy más interesado en los aspectos teóricos de esto.


Interesante idea, me preocupa un poco que incluso si se puede hacer, podría ser confuso. Por ejemplo, al definir una propiedad con iniciadores y getters no triviales, o cómo desambiguar Foo si el tipo declarante también contenía una propiedad llamada Foo.

Me pregunto si esto sería más fácil en un lenguaje más dinámico, o incluso con el tipo dinámico y DLR en C # 4.0.

Tal vez hoy en C # parte de la intención se puede lograr con lambdas:

void Main() { var foo = new Foo(); foo.Bar = "bar"; foo.Print = () => Console.WriteLine(foo.Bar); foo.Print(); } class Foo : IFoo { public String Bar { get; set; } public Action Print {get;set;} }


Mientras elaboremos una lista de deseos de la interfaz, me gustaría poder decirle al compilador que una clase implementa una interfaz fuera de la definición de la clase, incluso en un ensamblaje separado.

Por ejemplo, digamos que estoy trabajando en un programa para extraer archivos de diferentes formatos de archivo. Quiero poder implementar implementaciones existentes de diferentes bibliotecas, por ejemplo, SharpZipLib y una implementación comercial de PGP, y consumir ambas bibliotecas usando el mismo código sin crear nuevas clases. Entonces podría usar tipos de cualquier fuente en restricciones genéricas, por ejemplo.

Otro uso sería decirle al compilador que System.Xml.Serialization.XmlSerializer implementa la interfaz System.Runtime.Serialization.IFormatter (ya lo hace, pero el compilador no lo sabe).

Esto también podría usarse para implementar su solicitud, simplemente no de manera automática. Todavía tendrías que decirle explícitamente al compilador al respecto. No estoy seguro de cómo se vería la sintaxis, porque aún tendría que mapear manualmente los métodos y las propiedades en algún lugar, lo que significa mucha verborrea. Tal vez algo similar a los métodos de extensión.


No se puede hacer que un tipo anónimo haga nada excepto tener propiedades de solo lectura.

Citando la guía de programación de C # (tipos anónimos) :

"Los tipos anónimos son tipos de clase que constan de una o más propiedades públicas de solo lectura. No se permiten otros tipos de miembros de la clase, como métodos o eventos. Un tipo anónimo no se puede convertir en ninguna interfaz o tipo, excepto para el objeto".


Habría algunos problemas con miembros sobrecargados, indexadores e implementaciones de interfaz explícitas.

Sin embargo, probablemente podría definir la sintaxis de una manera que le permita resolver esos problemas.

Curiosamente, puedes acercarte mucho a lo que quieres con C # 3.0 escribiendo una biblioteca. Básicamente, podrías hacer esto:

Create<IFoo> ( new { Foo = "foo", Print = (Action)(() => Console.WriteLine(Foo)) } );

Que es bastante parecido a lo que quieres. Las principales diferencias son una llamada a "Crear" en lugar de la palabra clave "nueva" y el hecho de que necesita especificar un tipo de delegado.

La declaración de "Crear" se vería así:

T Create<T> (object o) { //... }

Luego usaría Reflection.Emit para generar una implementación de interfaz dinámicamente en tiempo de ejecución.

Sin embargo, esta sintaxis tiene problemas con las implementaciones de interfaz explícita y los miembros sobrecargados, que no podría resolver sin cambiar el compilador.

Una alternativa sería usar un inicializador de colección en lugar de un tipo anónimo. Eso se vería así:

Create { new Members<IFoo> { {"Print", ((IFoo @this)=>Console.WriteLine(Foo))}, {"Foo", "foo"} } }

Eso te permitiría:

  1. Maneje la implementación explícita de la interfaz especificando algo como "IEnumerable.Current" para el parámetro de cadena.
  2. Defina Members.Add para que no necesite especificar el tipo de delegado en el inicializador.

Debería hacer algunas cosas para implementar esto:

  1. Escribe un pequeño analizador para los nombres de tipo C #. Esto solo requiere ".", "[]", "<>", ID y los nombres de tipos primitivos, por lo que probablemente puedas hacer eso en unas pocas horas
  2. Implemente un caché para que solo genere una única clase para cada interfaz única
  3. Implementar el código Reflection.Emit gen. Esto probablemente demore alrededor de 2 días como máximo.

Podrías tener algo así como clases anónimas en Java:

using System; class Program { static void Main() { var f = new IFoo() { public String Foo { get { return "foo"; } } public void Print() { Console.WriteLine(Foo); } }; } } interface IFoo { String Foo { get; set; } void Print(); }


He utilizado en Java la clase Amonimous a través del "nuevo iftax IFoo () {...}" y es práctico y fácil cuando tienes que implementar rápidamente una interfaz simple.

Como muestra, sería bueno implementar IDisposable de esta manera en un objeto heredado utilizado una sola vez en lugar de derivar una nueva clase para implementarlo.


Requiere c # 4, pero la interfaz impromptu del marco de código abierto puede simular esto de la caja utilizando proxies DLR internamente. El rendimiento es bueno, aunque no tan bueno como si existiera el cambio propuesto.

using ImpromptuInterface.Dynamic;

...

var f = ImpromptuGet.Create<IFoo>(new{ Foo = "foo", Print = ReturnVoid.Arguments(() => Console.WriteLine(Foo)) });


¿No sería genial? Clase anónima en línea:

List<Student>.Distinct(new IEqualityComparer<Student>() { public override bool Equals(Student x, Student y) { return x.Id == y.Id; } public override int GetHashCode(Student obj) { return obj.Id.GetHashCode(); } })


Voy a volcar esto aquí. Lo escribí hace un tiempo, pero IIRC funciona bien.

Primero, una función auxiliar para tomar una MethodInfo y devolver un Type de Func o Action coincidente. Necesitas una rama para cada número de parámetros, desafortunadamente, y aparentemente me detuve a las tres.

static Type GenerateFuncOrAction(MethodInfo method) { var typeParams = method.GetParameters().Select(p => p.ParameterType).ToArray(); if (method.ReturnType == typeof(void)) { if (typeParams.Length == 0) { return typeof(Action); } else if (typeParams.Length == 1) { return typeof(Action<>).MakeGenericType(typeParams); } else if (typeParams.Length == 2) { return typeof(Action<,>).MakeGenericType(typeParams); } else if (typeParams.Length == 3) { return typeof(Action<,,>).MakeGenericType(typeParams); } throw new ArgumentException("Only written up to 3 type parameters"); } else { if (typeParams.Length == 0) { return typeof(Func<>).MakeGenericType(typeParams.Concat(new[] { method.ReturnType }).ToArray()); } else if (typeParams.Length == 1) { return typeof(Func<,>).MakeGenericType(typeParams.Concat(new[] { method.ReturnType }).ToArray()); } else if (typeParams.Length == 2) { return typeof(Func<,,>).MakeGenericType(typeParams.Concat(new[] { method.ReturnType }).ToArray()); } else if (typeParams.Length == 3) { return typeof(Func<,,,>).MakeGenericType(typeParams.Concat(new[] { method.ReturnType }).ToArray()); } throw new ArgumentException("Only written up to 3 type parameters"); } }

Y ahora el método que toma una interfaz como un parámetro genérico y devuelve un Type que implementa la interfaz y tiene un constructor (necesita ser llamado a través de Activator.CreateInstance ) tomando una función o Action para cada método / getter / setter. Sin embargo, necesitas saber el orden correcto para ponerlos en el constructor. Alternativamente (código comentado) puede generar una DLL que luego puede referenciar y usar el tipo directamente.

static Type GenerateInterfaceImplementation<TInterface>() { var interfaceType = typeof(TInterface); var funcTypes = interfaceType.GetMethods().Select(GenerateFuncOrAction).ToArray(); AssemblyName aName = new AssemblyName("Dynamic" + interfaceType.Name + "WrapperAssembly"); var assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( aName, AssemblyBuilderAccess.Run/*AndSave*/); // to get a DLL var modBuilder = assBuilder.DefineDynamicModule(aName.Name/*, aName.Name + ".dll"*/); // to get a DLL TypeBuilder typeBuilder = modBuilder.DefineType( "Dynamic" + interfaceType.Name + "Wrapper", TypeAttributes.Public); // Define a constructor taking the same parameters as this method. var ctrBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, funcTypes); // Start building the constructor. var ctrGenerator = ctrBuilder.GetILGenerator(); ctrGenerator.Emit(OpCodes.Ldarg_0); ctrGenerator.Emit( OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); // For each interface method, we add a field to hold the supplied // delegate, code to store it in the constructor, and an // implementation that calls the delegate. byte methodIndex = 0; foreach (var interfaceMethod in interfaceType.GetMethods()) { ctrBuilder.DefineParameter( methodIndex + 1, ParameterAttributes.None, "del_" + interfaceMethod.Name); var delegateField = typeBuilder.DefineField( "del_" + interfaceMethod.Name, funcTypes[methodIndex], FieldAttributes.Private); ctrGenerator.Emit(OpCodes.Ldarg_0); ctrGenerator.Emit(OpCodes.Ldarg_S, methodIndex + 1); ctrGenerator.Emit(OpCodes.Stfld, delegateField); var metBuilder = typeBuilder.DefineMethod( interfaceMethod.Name, MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot, interfaceMethod.ReturnType, interfaceMethod.GetParameters() .Select(p => p.ParameterType).ToArray()); var metGenerator = metBuilder.GetILGenerator(); metGenerator.Emit(OpCodes.Ldarg_0); metGenerator.Emit(OpCodes.Ldfld, delegateField); // Generate code to load each parameter. byte paramIndex = 1; foreach (var param in interfaceMethod.GetParameters()) { metGenerator.Emit(OpCodes.Ldarg_S, paramIndex); paramIndex++; } metGenerator.EmitCall( OpCodes.Callvirt, funcTypes[methodIndex].GetMethod("Invoke"), null); metGenerator.Emit(OpCodes.Ret); methodIndex++; } ctrGenerator.Emit(OpCodes.Ret); // Add interface implementation and finish creating. typeBuilder.AddInterfaceImplementation(interfaceType); var wrapperType = typeBuilder.CreateType(); //assBuilder.Save(aName.Name + ".dll"); // to get a DLL return wrapperType; }

Puede usar esto como, por ejemplo

public interface ITest { void M1(); string M2(int m2, string n2); string prop { get; set; } event test BoopBooped; } Type it = GenerateInterfaceImplementation<ITest>(); ITest instance = (ITest)Activator.CreateInstance(it, new Action(() => {Console.WriteLine("M1 called"); return;}), new Func<int, string, string>((i, s) => "M2 gives " + s + i.ToString()), new Func<String>(() => "prop value"), new Action<string>(s => {Console.WriteLine("prop set to " + s);}), new Action<test>(eh => {Console.WriteLine(eh("handler added"));}), new Action<test>(eh => {Console.WriteLine(eh("handler removed"));})); // or with the generated DLL ITest instance = new DynamicITestWrapper( // parameters as before but you can see the signature );