Как возвратить динамические типы возврата в методах? C#

UserControl: пользовательский элемент управления, заканчивающийся в .ascx, который состоит из других веб-элементов управления. Почти как небольшая версия aspx веб-страницы. Это состоит из UI (ascx) и codebehind. Не может быть снова использован в других проектах путем ссылки на DLL.

WebControl: управление размещается на веб-странице или в UserControl. Это состоит из одного или нескольких классов, работающих в тандеме, и размещается на aspx странице или в UserControl. WebControls не имеют UI "страницей" и должны представить их содержание непосредственно. Они могут быть снова использованы в других приложениях путем ссылки на их DLLs.

RenderedControl: не существует. Может быть синонимично с WebControl. Мог бы указать, что управление записано непосредственно в HttpResponse, а не представлено к aspx странице.

CompositeControl: Промежуток UserControls и WebControls. Они кодируют как UserControls, поскольку они состоят из других средств управления. Нет никакого графического UI для составления композита управления, и поддержка редактирования UI CompositeControls должна быть кодирована разработчиком управления. Составление композита сделано в codebehind. CompositeControls может быть снова использован в других проектах как WebControls.

5
задан Andrew 23 September 2009 в 10:12
поделиться

6 ответов

Вы решаете не ту проблему. Если у вас есть суперкласс A с подклассами B , C и т. Д., Которые имеют схожую функциональность, вы хотите сделать следующее:

  1. Сделайте A интерфейсом, который реализует B , C и т. Д. Код, который работает с экземплярами B или C , работает через интерфейс, предоставляемый A . Если вы можете определить общий набор операций, которые работают со всеми типами, то это все, что вам нужно сделать.

  2. Если вы не можете определить общий набор операций, например, у вас есть код, похожий на:

     А foo = GetA ();
    if (foo is B) {
     B bFoo = (B) foo;
     // Делаем что-нибудь с foo как B
    } else if (foo is C) {
     C cFoo = (C) foo;
     // Делаем что-нибудь с foo как C
    } ...
    

    Или даже это (что в основном то же самое, просто используется дополнительная информация для имитации того, что система типов уже предоставляет вам):

     A foo = GetA ();
    MyEnum enumeratedValue = foo.GetEnumeratedValue ();
    switch (enumeratedValue) {
     case MyEnum.B:
     B bFoo = (B) foo;
     // Делаем что-нибудь с foo как B
     сломать;
     case MyEnum.C:
     C cFoo = (C) foo;
     // Делаем что-нибудь с foo как C
     сломать;
    }
    

    Тогда вам действительно нужно сделать что-то вроде:

     A foo = GetA ();
    foo.DoSomething ();
    

    Где каждый подкласс будет реализовывать соответствующую ветвь оператора switch . На самом деле это лучше в нескольких отношениях:

    • Он использует меньше общего кода.
    • Поскольку реализации кейсов находятся в различных классах реализации, преобразование не требуется; они могут получить доступ ко всем переменным-членам напрямую.
    • Поскольку вы не создаете большой переключатель / case блок отдельно от фактического B и C , вы не рискуете случайно забыть добавить соответствующий case при добавлении нового подкласса. Если вы оставите метод DoSomething () вне подкласса A , вы получите ошибку времени компиляции.

Изменить : В ответ на ваш комментарий:

Если ваша подпрограмма DoSomething () должна работать с формой или другим элементом графического интерфейса пользователя, просто передайте этот элемент в метод. Например:

public class B : A {
    public void DoSomething(MyForm form) {
        form.MyLabel.Text = "I'm a B object!";
    }
}

public class C : A {
    public void DoSomething(MyForm form) {
        form.MyLabel.Text = "I'm a C object!";
    }
}

// elsewhere, in a method of MyForm:

A foo = GetA();
foo.DoSomething(this);

В качестве альтернативы, еще лучше было бы превратить ваши классы B и C в настраиваемые элементы управления, поскольку они, похоже, инкапсулируют логику отображения.

7
ответ дан 18 December 2019 в 08:29
поделиться

Вы можете создать общий метод:

public T GetAppointment<T>(int id) where T : tblAppointment 
{
    var singleAppointment = dc.tblAppointments.SingleOrDefault(a => a.appID == id);
    return (T)singleAppointment;
}

Но тогда вам нужно будет знать фактический тип объекта перед его вызовом ...

2
ответ дан 18 December 2019 в 08:29
поделиться

Ну, если вы используете C # 4, вы можете использовать динамическую типизацию ... но если вы хотите придерживаться статической типизации, я думаю, лучшее, что вы можете сделать предоставляет ожидаемый тип в качестве аргумента универсального типа и получает метод для выполнения преобразования для вас:

public T GetAppointment<T>(int id) where T : tblAppointment
{
    var singleAppointment = (from a in dc.tblAppointments
                                                    where a.appID == id
                                                    select a).SingleOrDefault();
    return (T) singleAppointment;

}

Вызовите это с помощью:

SpecificAppointment app = GetAppointment<SpecificAppointment>(10);

или используйте неявную типизацию:

var app = GetAppointment<SpecificAppointment>(10);

Это вызовет исключение во время выполнения, если приведение не выполняется.

Предполагается, что вызывающий абонент знает тип встречи (хотя они могут указать tblAppointment , если не знают). Не зная соответствующий тип встречи во время компиляции, трудно понять, как статическая типизация может оказать вам больше пользы, правда ...

7
ответ дан 18 December 2019 в 08:29
поделиться

Когда вы вызываете .GetType () , вы получаете тип среды выполнения объекта. Компилятор C # не знает, какой тип среды выполнения будет у вашего объекта. Он знает только, что ваш объект будет иметь тип, производный от tblAppointment , потому что вы сказали это в объявлении вашего метода, поэтому статический тип возвращаемого значения - tblAppointment . Поэтому tblAppointment - это все, к чему вы можете получить доступ, если вы не используете приведение, чтобы сообщить компилятору: «Я знаю, что во время выполнения эта ссылка будет ссылаться на объект этого типа, вставьте проверку времени выполнения и дайте мне ссылка на этот статический тип ».

Статическая типизация - это все о различии между типами, известными во время компиляции и во время выполнения. Если вы пришли с языка с динамической типизацией, такого как Smalltalk или Javascript, вам придется внести немало изменений в свои привычки программирования и мыслительные процессы. Например, если вам нужно сделать что-то с объектом, который зависит от его типа среды выполнения, решение часто состоит в использовании виртуальных функций - они отправляются на тип среды выполнения объекта.

Обновление: в вашем конкретном случае используйте виртуальные функции, это именно то, для чего они были созданы:

class tblAppointment
{
    protected abstract void ProcessAppointment () ;
}

sealed class tblBirthAppointment
{
    protected override void ProcessAppointment ()
    {
        // `this` is guaranteed to be tblBirthAppointment
        // do whatever you need
    }
}

...

Затем используйте

// will dispatch on runtime type
appointmentsRepo.GetAppointment (id).ProcessAppointment () ;
2
ответ дан 18 December 2019 в 08:29
поделиться

Вы можете создать другой метод для инкапсуляции приведения:

public tblSingleBirthAppointment GetBirthAppointment(int id)
{
    var singleAppointment = GetAppointment(id);

    if (singleAppointment != null)
    {
        return (tblSingleBirthAppointment)singleAppointment;
    }

    return null;
}

Этот метод сломается, если вы попытаетесь использовать его с идентификатором, который на самом деле не был назначением рождения, поэтому вы можете рассмотреть возможность проверки .

var viewSingleBirthAppointment = appointmentRepos.GetBirthAppointment(appointmentId);
1
ответ дан 18 December 2019 в 08:29
поделиться

Если вы возвращаете ссылку на дочерний тип, который является родительским типом, ссылка будет относиться к этому типу, и компилятор не позволит вам получить доступ ни к одному из членов дочернего типа, пока вы не приведете к этому типу. Это полиморфизм в действии :)

Хорошая новость в том, что вы не создаете новый объект, когда приводите ссылочный тип - вы просто меняете тип ссылки, которая указывает на уже имеющийся у вас объект, тем самым предоставляя вам доступ своим членам.

0
ответ дан 18 December 2019 в 08:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: