По предложению ispiro я нашел что-то, что должно охватывать все.
Поэтому я объявляю свои интерфейсы независимыми от базового представления, например,
public interface IPostNumber{}
public interface IPostNumberFrom : IPostNumber{}
public interface IPostNumberTo : IPostNumber{}
Они имеют полную общность интерфейса, такую как множественное наследование. Затем представление данных выполняется с помощью обобщенных c классов с неявным преобразованием:
public class CInt<T>
{
public int value;
public static implicit operator int(CInt<T> d) => d.value;
public static implicit operator CInt<T>(int b) => new CInt<T>() { value = b };
}
Функции, которые принимают IPostNumber
с int
, выполняются так:
private int TestPostNumberInt(CInt<IPostNumber> i) => i;
private int TestPostNumberFrom(CInt<IPostNumberFrom> i) => i;
CInt<IPostNumber> a = 4; // Works
Assert.Equal(1, TestPostNumberInt(1)); // Works
Assert.Equal(1, TestPostNumberFrom(a)); // Don't compile with IPostNumber into IPostNumberFrom
Теперь я всегда могу объявить CString<IPostNumber>
, если некоторые номера постов представлены в виде строки. Или функция может принять сам интерфейс IPostNumber
, если я сделаю какой-то его класс. Теперь одна небольшая проблема заключается в том, что если я хочу передать CInt<IPostNumberFrom>
в TestPostNumber
, метод должен быть generi c с T : IPostNumber
, например:
private int TestPostNumberInt<T>(CInt<T> i) where T : IPostNumber => i;
private int TestPostNumberIntFrom<T>(CInt<T> i) where T : IPostNumberFrom => i;
и затем generi c тип не будет обнаружен при использовании неявного преобразования (должен быть приведен). Но посмотрим, будет ли это важно.
Также для дальнейшего рассмотрения: у меня будет class CJSON<T> : CString<T>
. Из того, что я вижу, это работает, хотя argubly CJSON
может иметь и другие представления, например byte[]
в некотором контексте. (Но это далеко уходит). Так что просто нужно серьезно подумать о представлении и интерфейсах для моих концепций домена.