В специальном случае есть невероятно простое и короткое решение.
Сегодня я столкнулся с аналогичной проблемой, с внешним XML-файлом, который содержит значения TRUE / FALSE, которые должны иметь логическое значение значение.
Если для приложения не обязательно, чтобы десериализованный документ содержал собственный bool, но он просто требует десериализации его для чего-то, что ограничено любыми двумя альтернативными значениями, тогда можно просто использовать перечисление (здесь для атрибута в качестве примера):
public enum BOOL {FALSE, TRUE};
public MyClass
{
[XmlAttribute]
public BOOL MyStrangeBooleanAttribute {get; set;}
}
Это будет просто десериализовать без каких-либо проблем из элемента вроде этого
<MyClass MyStrangeBooleanAttribute = "TRUE" />
Конечно, это невозможно использовать свойство в коде для прямых логических операций, например
if (MyStrangeBooleanAttribute) // ... doesn't work
Я думаю, что, возможно, с этим можно было бы справиться, указав неявное преобразование, но я его не тестировал, потому что я не это нужно.
Если у класса Box
нет конструктора с T
, то вы можете создать класс, расширяющий Box
. Например:
class NewBox extends Box<NewBox> {
...
}
Затем вы можете создать экземпляр G
, например:
G<NewBox> g = new G<>(new NewBox());
Но в вашем случае Box имеет конструктор Box(T val){...}
, тогда NewBox
требуется соответствие конструктора super
] вроде:
class NewBox extends Box<NewBox> {
NewBox(NewBox val) {
super(val);
}
}
Чтобы создать его, вы должны получить нулевое значение, иначе это приведет к бесконечному вложению:
G<NewBox> g = new G<>(new NewBox(new NewBox(new NewBox(null))));
Обновление: , чтобы ответить Исходный вопрос: G <T extends Box<T>>
означает, что T
должен быть типом Box
или любым потомком Box
. Как вы правильно заметили, это приведет к бесконечной вложенности. Но вы все еще можете создать этот экземпляр без создания дополнительного класса (как указано выше с NewBox
), используя Wildcard и null
в качестве параметра для конструктора класса G
, например: 1125]
G<?> tg = new G<>(null);
Если вас беспокоит ограничение типа T extends Box<T>
, это означает, что только типы, которые могут быть указаны в качестве параметра типа, должны расширяться Box
.
Этот метод используется для указания дополнительных операций, которые вы можете выполнять с вашим типом (например, хорошо известным Comparable<T>
), так что на самом деле использование класса, а не интерфейса не очень распространено.
Позвольте привести пример. Скажем, у нас есть следующие операции
interface Op1<T>{
void doOp1(t: T): T
}
interface Op2<T> {
void doOp2(t: T): T
}
class MyClass implements Op1<MyClass>, Op2<MyClass>{
//By implementing Op1 and Op2 you
//specify that operations doOp1 and doOp2
// can be applied to variable of typr MyClass
}
И теперь вы хотите реализовать свой универсальный контейнер, который принимает элементы типов Op1
и Op2
, которые могут быть применены к
class MyContainer<T extends Op1<T> & Op2<T>>{
//you can apply doOp1 and doOp2 to any variable of the type T
}
MyContainer<MyClass> t = //... Ok
MyContainer<Integer> t = //... Not ok
[1111 ] В функциональном программировании подобное (но не совсем то же самое) называется классом типов