C# с использованием универсальных типов для представления частично загруженного дерева данныхC#

Место общения программистов C#
Ответить
Anonymous
 C# с использованием универсальных типов для представления частично загруженного дерева данных

Сообщение Anonymous »

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

Код: Выделить всё

public class Address
{
public string Line1 { get; set; }
public string City { get; set; }
}

public class Customer
{
public string Name { get; set; }
public Address Address { get; set; }
public ICollection Orders { get; set; }
}

public class Order
{
public int OrderNumber { get;  set; }
public ICollection[*] Lines { get; set; }
}

public class Line
{
public int Qty { get; set; }
public string Product { get; set; }
}
Классы имеют ссылки друг на друга, но иногда эти ссылки не загружаются, и вместо этого поля будут иметь значение NULL. Изменение этих свойств на значение NULL приводит к собственным проблемам, поскольку из-за этого свойства всегда необходимо проверять на значение NULL, даже если во время компиляции мы знаем, какие свойства загружаются, а какие нет.
Мое решение — это набор типов-оболочек, которые можно генерировать автоматически. Например, для Заказчика мы создаем следующие интерфейсы:

Код: Выделить всё

public interface NoCustomer { }

public interface ICustomer :  NoCustomer
where TAddr : NoAddress
where TOrders : NoOrder
{
string Name { get; set; }
}
Так, например, ICustomer означает клиента, у которого адрес и заказы не загружены, но ICustomer означает клиента, у которого адрес и заказы загружены, но строки заказов - нет. Мы можем использовать методы расширения, чтобы гарантировать, что во время компиляции вы не сможете получить доступ к одному из этих выгруженных объектов:

Код: Выделить всё

public static class CustomerExtensions
{
public static IAddress Address(this ICustomer customer)
where TOrders : NoOrder
{
...
}
}
Обратите внимание, что, поскольку типы ковариантны, мы можем писать функции, которые принимают Customer и передают ему Customer, или вообще использовать «более нагруженный» объект, когда нужен только «менее нагруженный» объект.
Все это хорошо, но проблема возникает, когда я пытаюсь сделать типы более эргономичными в использовании. По умолчанию типы становятся довольно многословными и, что еще хуже, в конечном итоге вы тратите много символов на разговоры о типах, которые даже не загружены. Например,

Код: Выделить всё

ICustomer
писать раздражает, и я бы предпочел написать

Код: Выделить всё

ICustomer
или что-то подобное. Последнее гораздо более понятно, поскольку отображаются только имена загруженных типов (Клиент и Заказ).
Однако мне трудно понять, как заставить это работать.
  • Мой первый подход — просто заменить интерфейсы NoCustomer, NoAddress и т. д. одним интерфейсом No. Проблема в том, что теперь все типы интерфейса наследуются от типа No, поэтому вы можете предоставлять неверные аргументы типа, и компилятор ничего не может с этим поделать (например, ICustomer будет нормально компилироваться!).
  • Мой второй подход — попытаться использовать оба типа NoCustomer, а также также общий тип No, который наследует от всех из них. Таким образом, мы могли бы написать ICustomer или, альтернативно, ICustomer, но не ICustomer. На первый взгляд кажется, что это сработает, но проблема в том, что ICustomer наследуется от ICustomer

    Подробнее здесь: https://stackoverflow.com/questions/798 ... ee-of-data
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»