Pregunta

En C # 3.0 y .NET 3.5, imagina que hay una interfaz:

public interface INameable
{
  string Name {get;}
}

y muchas clases inmutables que implementan la interfaz.

Me gustaría tener un solo método de extensión

public static T Rename<T>(this T obj) where T : INameable
{ 
  ...
}

que devuelve una instancia envuelta del objeto original con solo el nombre cambiado y todas las demás lecturas de propiedades y llamadas de método enrutadas al objeto original.

¿Cómo obtener una clase de envoltura genérica para esto, sin implementarla para todos los tipos de implementación INameable? ¿Crees que eso es posible?

¿Fue útil?

Solución

No, esto no es posible, a menos que T esté restringido para ser una interfaz o una clase con todos los miembros virtuales, y esta restricción no se puede especificar en el momento de la compilación (aunque podría escribir una verificación de tiempo de ejecución si está satisfecho con ese enfoque).

La razón por la que no puede hacerlo para tipos arbitrarios es que si toma un objeto de tipo T , debe devolver un objeto que sea asignable a T . Si paso un objeto que tiene el siguiente aspecto ...

public sealed class SomeClass : INameable
{
    public string Name { get; }
    public string Abc { get; }
}

... entonces no hay forma de que puedas crear otro tipo que sea asignable a SomeClass . No usar Reflection.Emit o cualquier otro método, porque el tipo está sellado.

Sin embargo, si está satisfecho con las restricciones que he mencionado, entonces podría usar algo como el framework Castle DynamicProxy para crear un tipo que proxies el objeto pasado e intercepte las llamadas para reenviar o volver a implementar como apropiado.

Otros consejos

Bueno, sí, es posible, pero implica generar código en la memoria.

Puede consultar Reflection.Emit y aquí .

Tenga en cuenta que implicará una gran cantidad de código.

Es decir, si asumo que te entiendo correctamente.

Esto es lo que creo que estás pidiendo:

SomeNameableObject a1 = new SomeNameableObject("ThisIsTheFirstName");
SomeNameableObject a2 = a1.Rename("ThisIsTheSecondName");
// a1 works, still has the name ThisIsTheFirstName
// a2 works, but everything is routed to a1,
//    except for the name, which is ThisIsTheSecondName

¿Eso es correcto?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top