Czy C# wspiera kowariancję typu return?
Pracuję z. NET framework i naprawdę chcę być w stanie zrobić niestandardowy typ strony, że wszystkie moja strona używa. Problem pojawia się, gdy próbuję uzyskać dostęp do strony z kontrolki. Chcę mieć możliwość powrotu określonego typu strony zamiast domyślnej. Jest na to jakiś sposób?
public class MyPage : Page
{
// My own logic
}
public class MyControl : Control
{
public MyPage Page { get; set; }
}
9 answers
Wygląda na to, że to, czego chcesz, to KOWARIANCJA typu return. C# nie obsługuje kowariancji typu powrotu.
KOWARIANCJA typu zwrotnego polega na tym, że nadpisujesz metodę klasy bazowej, która zwraca mniej specyficzny typ, z tą, która zwraca bardziej specyficzny typ:
abstract class Enclosure
{
public abstract Animal Contents();
}
class Aquarium : Enclosure
{
public override Fish Contents() { ... }
}
Jest to bezpieczne, ponieważ konsumenci treści za pośrednictwem obudowy oczekują zwierzęcia, a Akwarium obiecuje nie tylko spełnić ten wymóg, ale ponadto złożyć bardziej rygorystyczną obietnicę: że zwierzę jest zawsze ryba.
Ten rodzaj kowariancji nie jest obsługiwany w C# i jest mało prawdopodobne, aby kiedykolwiek był obsługiwany. Nie jest obsługiwany przez CLR. (Jest on wspierany przez C++, oraz przez implementację C++ / CLI na CLR; robi to poprzez generowanie magicznych metod pomocniczych, takich jak sugeruję poniżej.)
(Niektóre języki również obsługują formalny parametr contravariance -- że można zastąpić metodę, która zabiera rybę, metodą, która zabiera zwierzę. Ponownie, umowa została spełniona; podstawa Klasa wymaga, aby obchodzić się z każdą rybą, a klasa pochodna obiecuje nie tylko obchodzić się z rybami, ale z każdym zwierzęciem. Podobnie, C# i CLR nie obsługują formalnych parametrów typu contravariance.)
Sposób obejścia tego ograniczenia polega na zrobieniu czegoś w stylu:
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() { ... }
}
Teraz masz zarówno korzyści z nadpisania metody wirtualnej, jak i coraz silniejsze pisanie, gdy używasz czegoś typu Akwarium w czasie kompilacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-31 22:46:02
Umieszczenie tego w obiekcie MyControl zadziałałoby:
public new MyPage Page {get return (MyPage)Page; set;}'
Nie można nadpisać właściwości, ponieważ zwraca inny typ... ale możesz to przedefiniować.
Nie potrzebujesz kowariancji w tym przykładzie, ponieważ jest ona stosunkowo prosta. Wszystko, co robisz, to dziedziczenie obiektu bazowego Page
z MyPage
. Każda Control
, którą chcesz zwrócić MyPage
zamiast Page
, musi przedefiniować Page
Właściwość Control
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-18 21:39:56
Ta seria postów na blogu omawia szczegółowo problem kowariancji typu powrotu, nawet mówiąc o tym, jak to zrobić z IL.
Http://www.simple-talk.com/community/blogs/simonc/archive/2010/07/14/93495.aspx
Http://www.simple-talk.com/community/blogs/simonc/archive/2010/07/16/93516.aspx
Http://www.simple-talk.com/community/blogs/simonc/archive/2010/07/19/93562.aspx
Przepraszam za zamieszczanie linków, ale jest to dość szczegółowe a cytowanie fragmentów tutaj nie byłoby aż tak pomocne. Pokazuje, jak można to osiągnąć za pomocą kodu IL.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-26 17:47:22
Tak, wspiera kowariancję, ale zależy od tego, co dokładnie próbujesz osiągnąć.
Ja też często używam leków generycznych, co oznacza, że gdy robisz coś w stylu:
class X<T> {
T doSomething() {
}
}
class Y : X<Y> {
Y doSomethingElse() {
}
}
var Y y = new Y();
y = y.doSomething().doSomethingElse();
I nie "tracić" swoich typów.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-18 21:22:18
Z interfejsami obejrzałem to jawnie implementując Interfejs:
public interface IFoo {
IBar Bar { get; }
}
public class Foo : IFoo {
Bar Bar { get; set; }
IBar IFoo.Bar => Bar;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-29 13:41:45
Nie próbowałem, ale czy to nie działa?
YourPageType myPage = (YourPageType)yourControl.Page;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-18 21:21:48
Tak. Istnieje wiele sposobów, aby to zrobić, a to jest tylko jedna opcja:
Możesz sprawić, że Twoja strona zaimplementuje jakiś niestandardowy interfejs, który wyświetla metodę o nazwie "GetContext" lub coś takiego i zwraca konkretne informacje. Wtedy twoja kontrola może po prostu zażądać strony i rzucić:
var myContextPage = this.Page as IMyContextGetter;
if(myContextPage != null)
var myContext = myContextPage.GetContext();
Wtedy możesz użyć tego kontekstu, jak chcesz.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-18 21:21:51
Możesz uzyskać dostęp do swojej strony z dowolnego sterowania, wchodząc w drzewo nadrzędne. To jest
myParent = this;
while(myParent.parent != null)
myParent = myParent.parent;
* nie kompilował ani nie testował.
Lub uzyskać Stronę nadrzędną w bieżącym kontekście(zależy od wersji).
Wtedy lubię robić to: tworzę interfejs z funkcjami, których chcę używać w sterowaniu (na przykład IHostingPage)
Następnie oddaję Stronę nadrzędną 'IHostingPage host = (IHostingPage) Parent;' i jestem ustawiony na wywołanie funkcji na stronie I potrzebuję od mojej kontroli.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-18 21:26:57
Zrobię to w ten sposób:
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; } }
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-18 10:06:41