За и против 'новых' свойств в C# / .NET?

Использование объекта JSONObject для отправки параметров означает, что параметры будут в формате JSON в теле запроса HTTP POST:

Map<String, String> params = new HashMap<String, String>();
params.put("tag", "test");
params.put("tag2", "test2");
JSONObject jsonObj = new JSONObject(params);

Создаст этот объект JSON и вставит его в тело запроса HTTP POST. :

{"tag":"test","tag2":"test2"}

Затем сервер должен декодировать JSON, чтобы понять эти параметры POST.

Но обычно параметры HTTP POST записываются в теле как:

tag=test&tag2=test2

Но СЕЙЧАС здесь возникает вопрос, почему Volley устанавливается таким образом?

Сервер читает HTTP POST метод должен по стандарту всегда пытаться читать параметры также в JSON (кроме простого текста), и поэтому сервер, который не выполняет, является плохим сервером?

Или вместо этого тело HTTP POST с параметрами в JSON не чего обычно хочет сервер?

9
задан oɔɯǝɹ 3 June 2009 в 12:09
поделиться

6 ответов

Я думаю, что это хороший образец. Это упрощает явное использование производных типов, устраняя необходимость приводить результат, и не «нарушает» поведение базового класса. Фактически, аналогичный шаблон используется в некоторых классах в BCL, например, посмотрите иерархию классов DbConnection:

  • DbConnection.CreateCommand () возвращает DbCommand
  • SqlConnection.CreateCommand () скрывает базовую реализацию с помощью 'new' чтобы вернуть SqlCommand.
  • (другие реализации DbConnection делают то же самое)

Итак, если вы манипулируете объектом подключения через переменную DbConnection, CreateCommand вернет DbCommand; если вы управляете им через переменную SqlConnection, CreateCommand вернет SqlCommand, избегая приведения, если вы

7
ответ дан 4 December 2019 в 07:35
поделиться

Я бы предпочел сделать тип универсальным:

public abstract class Order<TDelivery> where TDelivery : Delivery
{
    public TDelivery Delivery { ... }
    ...
}

public class CustomerOrder : Order<ParcelDelivery>
{
    ...
}

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

CustomerOrder customerOrder = new CustomerOrder();
Order order = customerOrder;
order.Delivery = new NonParcelDelivery(); // Succeeds!

ParcelDelivery delivery = customerOrder.Delivery; // Returns null

Ой.

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

Если вы не хотите идти по общему пути, я бы представил действительно новое свойство (с другим именем).

11
ответ дан 4 December 2019 в 07:35
поделиться

Вы можете использовать дженерики.

// order (base) class
public abstract class Order<TDeliveryStrategy> where TDeliveryStrategy : DeliveryStrategy
{
    private TDeliveryStrategy delivery;

    protected Order(TDeliveryStrategy delivery)
    {
        this.delivery = delivery;
    }

    public TDeliveryStrategy Delivery
    {
        get { return delivery; }
        protected set { delivery = value; }
    }
}

public class CustomerOrder : Order<ParcelDelivery>
{
    public CustomerOrder()
        : base(new ParcelDelivery())
    { }
}
5
ответ дан 4 December 2019 в 07:35
поделиться

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

public abstract class Order
{
    protected Order(DeliveryStrategy delivery)
    {
        Delivery = delivery;
    }

    public virtual DeliveryStrategy Delivery { get; protected set; }
}

public class CustomerOrder : Order
{
    public CustomerOrder()
        : base(new ParcelDelivery())
    { }

    public DeliveryStrategy Delivery { get; protected set; } 
}

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

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

1
ответ дан 4 December 2019 в 07:35
поделиться

По моему мнению, использование ключевого слова new для скрытия доступных для записи свойств из базового класса - плохая идея. Ключевое слово new позволяет скрыть член базового класса в производном классе, а не переопределять его. Это означает, что вызовы таких членов с использованием ссылки базового класса по-прежнему обращаются к коду базового класса, а не к коду производного класса. В C # есть ключевое слово virtual, которое позволяет производным классам фактически переопределять реализацию, а не просто скрывать ее. Есть достаточно хорошая статья здесь , в которой рассказывается о различиях.

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

Часто значение наличия базового класса состоит в том, чтобы позволить пользователям вашего кода полиморфно обрабатывать типы. Что произойдет с вашей реализацией, если кто-то установит свойство Delivery, используя ссылку на базовый класс? Будет ли производный класс сломан, если свойство Delivery НЕ является экземпляром ParcelDelivery? Вот вопросы такого рода, которые вам нужно задать себе об этом выборе реализации.

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

Как уже упоминалось в некоторых других сообщениях, вы можете использовать дженерики как способ достижения различных типов свойств доставки . Пример Джона неплохо демонстрирует это. Есть одна проблема с подходом дженериков, если вам нужно унаследовать от CustomerOrder и изменить свойство Delivery на новый тип.

Существует альтернатива дженерикам. Вам нужно подумать, действительно ли вам нужно настраиваемое свойство в вашем случае. Если вы избавитесь от установщика в свойстве Delivery, проблемы, возникающие при использовании класса Order, исчезнут напрямую. Поскольку вы устанавливаете свойство доставки с помощью параметров конструктора, вы можете гарантировать, что все заказы имеют правильный тип стратегии.

Как уже упоминалось в некоторых других сообщениях, вы можете использовать дженерики как способ достижения различных типов свойств доставки. Пример Джона неплохо демонстрирует это. Есть одна проблема с подходом дженериков, если вам нужно унаследовать от CustomerOrder и изменить свойство Delivery на новый тип.

Существует альтернатива дженерикам. Вам нужно подумать, действительно ли вам нужно настраиваемое свойство в вашем случае. Если вы избавитесь от установщика в свойстве Delivery, проблемы, возникающие при использовании класса Order, исчезнут напрямую. Поскольку вы устанавливаете свойство доставки с помощью параметров конструктора, вы можете гарантировать, что все заказы имеют правильный тип стратегии.

Как уже упоминалось в некоторых других сообщениях, вы можете использовать дженерики как способ достижения различных типов свойств доставки. Пример Джона неплохо демонстрирует это. Есть одна проблема с подходом дженериков, если вам нужно унаследовать от CustomerOrder и изменить свойство Delivery на новый тип.

Существует альтернатива дженерикам. Вам нужно подумать, действительно ли вам нужно настраиваемое свойство в вашем случае. Если вы избавитесь от установщика в свойстве Delivery, проблемы, возникающие при использовании класса Order, исчезнут напрямую. Поскольку вы устанавливаете свойство доставки с помощью параметров конструктора, вы можете гарантировать, что все заказы имеют правильный тип стратегии.

Пример очень хорошо демонстрирует это. Есть одна проблема с подходом дженериков, если вам нужно унаследовать от CustomerOrder и изменить свойство Delivery на новый тип.

Существует альтернатива дженерикам. Вам нужно подумать, действительно ли вам нужно настраиваемое свойство в вашем случае. Если вы избавитесь от установщика в свойстве Delivery, проблемы, возникающие при использовании класса Order, исчезнут напрямую. Поскольку вы устанавливаете свойство доставки с помощью параметров конструктора, вы можете гарантировать, что все заказы имеют правильный тип стратегии.

Пример очень хорошо демонстрирует это. Есть одна проблема с подходом дженериков, если вам нужно унаследовать от CustomerOrder и изменить свойство Delivery на новый тип.

Существует альтернатива дженерикам. Вам нужно подумать, действительно ли вам нужно настраиваемое свойство в вашем случае. Если вы избавитесь от установщика в свойстве Delivery, проблемы, возникающие при использовании класса Order, исчезнут напрямую. Поскольку вы устанавливаете свойство доставки с помощью параметров конструктора, вы можете гарантировать, что все заказы имеют правильный тип стратегии.

Вам нужно подумать, действительно ли вам нужно настраиваемое свойство в вашем случае. Если вы избавитесь от установщика в свойстве Delivery, проблемы, возникающие при использовании класса Order, исчезнут напрямую. Поскольку вы устанавливаете свойство доставки с помощью параметров конструктора, вы можете гарантировать, что все заказы имеют правильный тип стратегии.

Вам нужно подумать, действительно ли вам нужно настраиваемое свойство в вашем случае. Если вы избавитесь от установщика в свойстве Delivery, проблемы, возникающие при использовании класса Order, исчезнут напрямую. Поскольку вы устанавливаете свойство доставки с помощью параметров конструктора, вы можете гарантировать, что все заказы имеют правильный тип стратегии.

3
ответ дан 4 December 2019 в 07:35
поделиться

Рассмотрите следующий подход:

public interface IOrder
{
    public DeliveryStrategy Delivery
    {
        get;
    }
}

// order (base) class
public abstract class Order : IOrder
{
    protected readonly DeliveryStrategy delivery;

    protected Order(DeliveryStrategy delivery)
    {
        this.delivery = delivery;
    }

    public DeliveryStrategy Delivery
    {
        get { return delivery; }
    }
}

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

public class CustomerOrder : Order
{
    public CustomerOrder()
        : base(new ParcelDelivery())
    { }

    public ParcelDelivery Delivery
    {
        get { return (ParcelDelivery)base.Delivery; }
    }


    DeliveryStrategy IOrder.Delivery
    {
        get { return base.Delivery}
    }
}

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

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

поля readonly всегда предпочтительнее, где это возможно. Они делают неизменность ясной.

1
ответ дан 4 December 2019 в 07:35
поделиться
Другие вопросы по тегам:

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