Estoy trabajando con el marco .NET y realmente quiero poder crear un tipo de página personalizado que utilice todo mi sitio web. El problema surge cuando intento acceder a la página desde un control. Quiero poder devolver mi tipo específico de página en lugar de la página predeterminada. ¿Hay alguna forma de hacer esto?
public class MyPage : Page
{
// My own logic
}
public class MyControl : Control
{
public MyPage Page { get; set; }
}
c#
covariance
Kyle Sletten
fuente
fuente
Respuestas:
ACTUALIZACIÓN: Esta respuesta se escribió en 2011. Después de dos décadas de personas que proponen la covarianza de tipo de retorno para C #, parece que finalmente se implementará; Estoy bastante sorprendido. Consulte la parte inferior de https://devblogs.microsoft.com/dotnet/welcome-to-c-9-0/ para ver el anuncio; Estoy seguro de que seguirán los detalles.
Parece que lo que desea es una covarianza de tipo de retorno. C # no admite la covarianza de tipo de retorno.
La covarianza del tipo de retorno es donde anula un método de clase base que devuelve un tipo menos específico con uno que devuelve un tipo más específico:
abstract class Enclosure { public abstract Animal Contents(); } class Aquarium : Enclosure { public override Fish Contents() { ... } }
Esto es seguro porque los consumidores de Contenidos vía Enclosure esperan un Animal, y Aquarium promete no solo cumplir con ese requisito, sino además, hacer una promesa más estricta: que el animal es siempre un pez.
Este tipo de covarianza no se admite en C # y es poco probable que lo sea alguna vez. No es compatible con CLR. (Es compatible con C ++ y con la implementación de C ++ / CLI en CLR; lo hace generando métodos de ayuda mágicos del tipo que sugiero a continuación).
(Algunos lenguajes también admiten contravarianza de tipo de parámetro formal, que puede anular un método que toma un pez con un método que toma un animal. Una vez más, el contrato se cumple; la clase base requiere que se manipule cualquier pez y el derivado class promete no solo manejar peces, sino cualquier animal. De manera similar, C # y CLR no admiten la contravarianza de tipo de parámetro formal.
La forma en que puede evitar esta limitación es hacer algo como:
abstract class Enclosure { protected abstract Animal GetContents(); public Animal Contents() { return this.GetContents(); } } class Aquarium : Enclosure { protected override Animal GetContents() { return this.Contents(); } public new Fish Contents() { ... } }
Ahora obtiene los beneficios de anular un método virtual y una escritura más fuerte cuando usa algo del tipo Acuario en tiempo de compilación.
fuente
Con las interfaces lo resolví implementando explícitamente la interfaz:
public interface IFoo { IBar Bar { get; } } public class Foo : IFoo { Bar Bar { get; set; } IBar IFoo.Bar => Bar; }
fuente
Colocar esto en el objeto MyControl funcionaría:
public new MyPage Page {get return (MyPage)Page; set;}'
No puede anular la propiedad porque devuelve un tipo diferente ... pero puede redefinirlo.
No necesita covarianza en este ejemplo, ya que es relativamente simple. Todo lo que estás haciendo es heredar el objeto base
Page
deMyPage
. CualquieraControl
que desee devolver enMyPage
lugar dePage
debe redefinir laPage
propiedad delControl
fuente
Sí, admite la covarianza, pero depende de lo que esté tratando de lograr exactamente.
También tiendo a usar mucho los genéricos para las cosas, lo que significa que cuando haces algo como:
class X<T> { T doSomething() { } } class Y : X<Y> { Y doSomethingElse() { } } var Y y = new Y(); y = y.doSomething().doSomethingElse();
Y no "perder" tus tipos.
fuente
Esta es una función para el próximo C # 9.0 (.Net 5) de la cual puede descargar una versión preliminar ahora.
El siguiente código construye ahora con éxito (sin dar:
error CS0508: 'Tiger.GetFood()': return type must be 'Food' to match overridden member 'Animal.GetFood()'
)class Food { } class Meat : Food { } abstract class Animal { public abstract Food GetFood(); } class Tiger : Animal { public override Meat GetFood() => default; } class Program { static void Main() => new Tiger(); }
fuente
No lo he probado, pero ¿no funciona?
fuente
Si. Hay varias formas de hacer esto, y esta es solo una opción:
Puede hacer que su página implemente alguna interfaz personalizada que exponga un método llamado "GetContext" o algo, y devuelva su información específica. Entonces su control puede simplemente solicitar la página y transmitir:
var myContextPage = this.Page as IMyContextGetter; if(myContextPage != null) var myContext = myContextPage.GetContext();
Entonces puedes usar ese contexto como quieras.
fuente
Puede acceder a su página desde cualquier control subiendo por el árbol principal. Es decir
myParent = this; while(myParent.parent != null) myParent = myParent.parent;
* No compiló ni probó.
O obtenga la página principal en el contexto actual (depende de su versión).
Entonces lo que me gusta hacer es esto: creo una interfaz con las funciones que quiero usar en el control (por ejemplo, IHostingPage)
Luego lanzo la página principal 'IHostingPage host = (IHostingPage) Parent;' y estoy listo para llamar a la función en la página que necesito desde mi control.
fuente
Lo haré de esta manera:
class R { public int A { get; set; } } class R1: R { public int B { get; set; } } class A { public R X { get; set; } } class B : A { private R1 _x; public new R1 X { get => _x; set { ((A)this).X = value; _x = value; } } }
fuente