C#: Переопределение типов возврата

Я предпочитаю делать это без делегатов и сегментов. Это можно сделать с помощью пользовательского init или установив дополнительные значения.

1. Custom init

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB(string: "Blabla", completionClosure: { success in
      print(success)
    })
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  private let completionClosure: ((Bool) -> Void)
  init(string: String, completionClosure: ((Bool) -> Void)) {
    self.completionClosure = completionClosure
    super.init(nibName: nil, bundle: nil)
    title = string
  }

  func finishWork() {
    completionClosure()
  }
}

2. Факультативные переменные

class ViewControllerA: UIViewController {
  func openViewControllerB() {
    let viewController = ViewControllerB()
    viewController.string = "Blabla"
    viewController.completionClosure = { success in
      print(success)
    }
    navigationController?.pushViewController(animated: true)
  }
}

class ViewControllerB: UIViewController {
  var string: String? {
    didSet {
      title = string
    }
  }
  var completionClosure: ((Bool) -> Void)?

  func finishWork() {
    completionClosure?()
  }
}
73
задан Daniel Daranas 26 June 2009 в 12:47
поделиться

8 ответов

А как насчет универсального базового класса?

public class Poo { }
public class RadioactivePoo : Poo { }

public class BaseAnimal<PooType> 
    where PooType : Poo, new() {
    PooType Excrement {
        get { return new PooType(); }
    }
}

public class Dog : BaseAnimal<Poo> { }
public class Cat : BaseAnimal<RadioactivePoo> { }

РЕДАКТИРОВАТЬ : Новое решение, использующее методы расширения и интерфейс маркера ...

public class Poo { }
public class RadioactivePoo : Poo { }

// just a marker interface, to get the poo type
public interface IPooProvider<PooType> { }

// Extension method to get the correct type of excrement
public static class IPooProviderExtension {
    public static PooType StronglyTypedExcrement<PooType>(
        this IPooProvider<PooType> iPooProvider) 
        where PooType : Poo {
        BaseAnimal animal = iPooProvider as BaseAnimal;
        if (null == animal) {
            throw new InvalidArgumentException("iPooProvider must be a BaseAnimal.");
        }
        return (PooType)animal.Excrement;
    }
}

public class BaseAnimal {
    public virtual Poo Excrement {
        get { return new Poo(); }
    }
}

public class Dog : BaseAnimal, IPooProvider<Poo> { }

public class Cat : BaseAnimal, IPooProvider<RadioactivePoo> {
    public override Poo Excrement {
        get { return new RadioactivePoo(); }
    }
}

class Program { 
    static void Main(string[] args) {
        Dog dog = new Dog();
        Poo dogPoo = dog.Excrement;

        Cat cat = new Cat();
        RadioactivePoo catPoo = cat.StronglyTypedExcrement();
    }
}

Таким образом, Dog и Cat наследуют от Животное (как отмечено в комментариях, мое первое решение не сохранило наследование).
Необходимо явно пометить классы с помощью интерфейса маркера, что болезненно, но, возможно, это может дать вам некоторые идеи ...

ВТОРОЙ РЕДАКТИРОВАНИЕ @Svish: Я изменил код, чтобы явно показать, что метод расширения является никоим образом не применяя тот факт, что iPooProvider наследуется от BaseAnimal . Что вы имеете в виду под «еще более строгой типизацией»?

47
ответ дан 24 November 2019 в 12:22
поделиться

Может помочь, если RadioactivePoo получен из poo, а затем использовать дженерики.

0
ответ дан 24 November 2019 в 12:22
поделиться

Поправьте меня, если я ошибаюсь, но не весь смысл поллиморфизма в возможности вернуть RadioActivePoo если он наследуется от Пу,

2
ответ дан 24 November 2019 в 12:22
поделиться

Существует также этот вариант (явная реализация интерфейса)

public class Cat:Animal
{
  Poo Animal.Excrement { get { return Excrement; } }
  public RadioactivePoo Excrement { get { return new RadioactivePoo(); } }
}

Вы теряете возможность использовать базовый класс для реализации Cat, но с другой стороны, вы сохраняете полиморфизм между Кошка и собака.

Но я сомневаюсь, что добавленная сложность того стоит.

9
ответ дан 24 November 2019 в 12:22
поделиться

Это называется ковариацией возвращаемого типа и не поддерживается в C # или .NET в целом, несмотря на пожелания некоторых людей.

Что я сделал бы ту же сигнатуру, но добавил бы дополнительное предложение ENSURE к производному классу, в котором я гарантирую, что оно вернет RadioActivePoo . Короче говоря, я бы сделал через дизайн по контракту то, что я не могу сделать с помощью синтаксиса.

Другие предпочитают подделать вместо этого. Думаю, это нормально, но я стараюсь экономить «инфраструктурные» строки кода. Если семантика кода достаточно ясна, я счастлив, и дизайн по контракту позволяет мне добиться этого, хотя это и не механизм времени компиляции.

То же самое для дженериков, которые другие ответы предлагать.

31
ответ дан 24 November 2019 в 12:22
поделиться

Попробуйте следующее:

namespace ClassLibrary1
{
    public interface Animal
    {   
        Poo Excrement { get; }
    }

    public class Poo
    {
    }

    public class RadioactivePoo
    {
    }

    public class AnimalBase<T>
    {   
        public virtual T Excrement
        { 
            get { return default(T); } 
        }
    }


    public class Dog : AnimalBase<Poo>
    {  
        // No override, just return normal poo like normal animal
    }

    public class Cat : AnimalBase<RadioactivePoo>
    {  
        public override RadioactivePoo Excrement 
        {
            get { return new RadioactivePoo(); } 
        }
    }
}
2
ответ дан 24 November 2019 в 12:22
поделиться

Почему бы не определить защищенный виртуальный метод, который создает «Excrement», и оставить общедоступное свойство, которое возвращает «Excrement», не виртуальным. Затем производные классы могут переопределить тип возвращаемого значения базового класса.

В следующем примере я делаю Excrement не виртуальным, но предоставляю свойство ExcrementImpl, чтобы позволить производным классам предоставлять правильный Poo. Затем производные типы могут переопределить тип возвращаемого значения Excrement, скрыв реализацию базового класса.

Пример:

namepace ConsoleApplication8

{
public class Poo { }

public class RadioactivePoo : Poo { }

public interface Animal
{
    Poo Excrement { get; }
}

public class AnimalBase
{
    public Poo Excrement { get { return ExcrementImpl; } }

    protected virtual Poo ExcrementImpl
    {
        get { return new Poo(); }
    }
}

public class Dog : AnimalBase
{
    // No override, just return normal poo like normal animal
}

public class Cat : AnimalBase
{
    protected override Poo ExcrementImpl
    {
        get { return new RadioactivePoo(); }
    }

    public new RadioactivePoo Excrement { get { return (RadioactivePoo)ExcrementImpl; } }
}
}
4
ответ дан 24 November 2019 в 12:22
поделиться

1.) Любой сценарий CGI, который может взаимодействовать с базой данных и понимать JSON, или другой формат по вашему выбору, будет выполнять работу.

Однако, если вы знакомы с Джанго, построение вашего сервера поверх Джанго было бы самым простым, в смысле того, что вы должны узнать и сколько кода приложения вы должны написать. Казалось бы, простой сценарий CGI может получиться довольно сложным, если писать его с нуля.

Я обнаружил, что django-поршневой является удобным приложением Django для быстрого написания API-сервера в стиле REST. Он поддерживает JSON, поэтому он должен легко взаимодействовать с вашей игрой JavaScript.

2.) Самый случайный взломщик пойдет на повторную атаку и ее варианты: заглянуть в источник страницы и выполнить функцию JavaScript, перехватить HTTP-запросы и повторно отправить его (должно быть легко с дополнением Firefox, как изменения данных).

Для противодействия первому можно запутать исходный код и тело HTTP;

  • Уменьшить код JavaScript
  • Закодировать сообщение, отправляемое на сервер, с помощью Base64 или другого алгоритма кодирования

Последнее можно предотвратить, потребовав от всех запросов на обновление включения одноразового пароля («маркер сеанса» в статье Википедии ), которая была недавно

-121--4320846-

Я думаю, что нашел способ, который не зависит от дженериков или методов расширения, а скорее от скрытия метода. Он может сломать полиморфизм, однако, поэтому будьте особенно осторожны, если вы в дальнейшем наследуете от Кота.

Я надеюсь, что этот пост все еще может помочь кому-то, несмотря на опоздание на 8 месяцев.

public interface Animal
{
    Poo Excrement { get; }
}

public class Poo
{
}

public class RadioActivePoo : Poo
{
}

public class AnimalBase : Animal
{
    public virtual Poo Excrement { get { return new Poo(); } }
}

public class Dog : AnimalBase
{
    // No override, just return normal poo like normal animal
}

public class CatBase : AnimalBase
{
    public override Poo Excrement { get { return new RadioActivePoo(); } }
}

public class Cat : CatBase
{
    public new RadioActivePoo Excrement { get { return (RadioActivePoo) base.Excrement; } }
}
1
ответ дан 24 November 2019 в 12:22
поделиться
Другие вопросы по тегам:

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