reales - Pasar los parámetros C#que pueden "ajustarse" a una interfaz, pero en realidad no implementarla
libro de android studio en español pdf (7)
En una especie de no relacionado, esto es algo que comúnmente se hace en otros idiomas, como Scala y Haskell.
Se conoce como el uso de lo que se llama "clases de tipo". Las clases de tipos esencialmente le permiten definir el comportamiento para un tipo como si implementara explícitamente una interfaz, sin que realmente lo requiriera. Puedes leer más sobre esto here .
Nota: Sé que esta es una idea horrible en la práctica; Solo tengo curiosidad sobre lo que el CLR le permite hacer, con el objetivo de crear algún tipo de preprocesador ''modificar una clase después de crearlo''.
Supongamos que tengo la siguiente clase, que se definió en otro ensamblaje, por lo que no puedo cambiarla.
class Person {
public string Greet() => "Hello!";
}
Ahora defino una interfaz y un método, como el siguiente:
interface IGreetable {
string Greet();
}
// ...
void PrintGreeting(IGreetable g) => Console.WriteLine(g.Greet());
La clase Person
no implementa explícitamente IGreetable
, pero podría prescindir de cualquier modificación de sus métodos.
Con eso, ¿hay alguna forma en absoluto, utilizando Reflection, DLR o cualquier otra cosa, en la que una instancia de Person
pueda pasar satisfactoriamente a PrintGreeting
sin modificar ninguno de los códigos anteriores?
Esto puede ser bastante fácil pronto. Las clases de tipo pueden ser introducidas a C # como shapes donde podrá definir características de una clase y código contra esa forma y luego hacer uso de su código con cualquier tipo que coincida sin que el autor de ese código tenga que declarar nada, más o menos como describes
Lo más parecido en C # en este momento es quizás cómo foreach
funciona con un tipo que tiene un GetEnumerator()
devuelve un objeto de un tipo con MoveNext()
y Current
incluso si no implementan IEnumerable
etc. solo mientras está construido. en concepto que trata el compilador, aquí podría definirlos.
Curiosamente, también te permitirá definir miembros estáticos.
Intenta usar la biblioteca Impromptu-Interface
[La interfaz Impromptu-Interface] para permitir envolver cualquier objeto (estático o dinámico) con una interfaz estática aunque no herede de ella. Hace esto emitiendo código de enlace dinámico en caché dentro de un proxy.
Esto te permite hacer algo como esto:
var person = new Person();
var greeter = person.ActLike<IGreetable>();
No creo que esto sea posible. El compilador necesita ver algo que implementa explícitamente la interfaz o clase para que el compilador pueda confirmar que todo está implementado.
Si pudieras hacerlo usando la redirección, podrías dejar de implementar algo. Y eso va en contra del enfoque de seguridad adoptado por .NET.
Puede usar un objeto envoltorio dynamic
para conectarlo usted mismo, pero pierde seguridad tipo dentro de la clase de envoltura:
class GreetableWrapper : IGreetable
{
private dynamic _wrapped;
public GreetableWrapper(dynamic wrapped)
{
_wrapped = wrapped;
}
public string Greet()
{
return _wrapped.Greet();
}
}
static void PrintGreeting(IGreetable g) => Console.WriteLine(g.Greet());
static void Main(string[] args)
{
PrintGreeting(new GreetableWrapper(new Person()));
Console.ReadLine();
}
Si tiene el control del código externo y está dispuesto a envolver el objeto (y parece que todas las respuestas aquí se ajustan), el enlace dinámico y las bibliotecas como Impromptu-Interface me parecen un montón de problemas para algo que es esencialmente un un trazador de líneas.
class GreetablePerson : Person, IGreetable { }
Y tu estas listo.
Cuando el compilador está creando la clase GreetablePerson, el método de Person termina haciendo una implementación implícita de la interfaz, y todo "simplemente funciona". La única irritación es que el código externo tiene que crear instancias de objetos GreetablePerson
, pero en la terminología estándar orientada a objetos, una instancia de GreetablePerson
es una instancia de Person
, por lo que me parece una respuesta válida a la pregunta.
Si los requisitos se modifican de modo que también tenga instancias preexistentes de Persona, entonces algo como Impromptu-Interface puede ser más tentador, pero aun así es posible que desee considerar darle a GreetablePerson
un constructor que GreetablePerson
desde Person. Elegir la mejor ruta de acceso desde allí requiere obtener más detalles sobre los requisitos y los detalles de implementación reales de la clase de persona en cuestión.
Una opción es crear una clase contenedora sobre la persona y pasar esta envoltura al método, el envoltorio debe implementar explícitamente la interfaz.