将抽象 class 中的泛型 属性 定义为实现 class 的类型
Defining generic property in abstract class as a type of the implementing class
假设我有一个 class 比如:
public abstract class Foo {
public List<TypeOfImplementingClassHere> container;
}
所以当另一个 class 实现它时,像这样说:
public class Bar extends Foo {
public Bar(List<Bar> container) {
this.container = container;
}
}
我们可以有一个指向容器的指针,我们可以在其中找到我们的 Bar
对象。你能在 Java 或 C# 中做到这一点吗?
当然可以。
试试这个。
public abstract class Foo<T extends Foo<T>> {
public List<T> container;
protected Foo() {
enforceConstraints();
}
private void enforceConstraints() {
boolean valid = true;
try {
valid =
((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0]
.equals(
this.getClass()
);
} catch (ClassCastException cce) {
valid = false;
}
if (!valid) {
String name = this.getClass().getSimpleName();
throw new IllegalImplementationException(
name + " must be declared as "+ "\"class " + name + " extends Foo<"+name+">\"");
}
}
private static class IllegalImplementationException extends RuntimeException {
IllegalImplementationException(String message) {
super(message);
}
}
}
在 C# 中更简单:
public class Foo<T> where T : Foo<T> {
public List<T> container;
protected Foo() {
enforceConstraints();
}
private void enforceConstraints() {
if (!this.GetType().Equals(typeof(T))) {
String name = this.GetType().Name;
throw new IllegalImplementationException(
name + " must be declared as " + "\"class " + name + " : Foo<" + name + ">\"");
}
}
}
public class IllegalImplementationException : Exception {
public IllegalImplementationException(String message) : base(message) {}
}
enforceConstraints()
可以在发送到生产环境时删除。请注意,这会强制通过反射以我们的方式限制泛型参数,因为此处所需的类型限制在 Java 或 C# 中不可用。因为我们完全通过反射来强制执行约束,所以没有必要添加约束 T extends Foo<T>
,但这可以防止误用。请注意,使用约束 Foo<T extends Foo<T>
,您可以有 Bar1 extends Foo<Bar1>
和 Bar2 extends Foo<Bar1>
,但我们不想要第二种类型,因此为什么需要反射。
假设我有一个 class 比如:
public abstract class Foo {
public List<TypeOfImplementingClassHere> container;
}
所以当另一个 class 实现它时,像这样说:
public class Bar extends Foo {
public Bar(List<Bar> container) {
this.container = container;
}
}
我们可以有一个指向容器的指针,我们可以在其中找到我们的 Bar
对象。你能在 Java 或 C# 中做到这一点吗?
当然可以。
试试这个。
public abstract class Foo<T extends Foo<T>> {
public List<T> container;
protected Foo() {
enforceConstraints();
}
private void enforceConstraints() {
boolean valid = true;
try {
valid =
((ParameterizedType) this.getClass().getGenericSuperclass())
.getActualTypeArguments()[0]
.equals(
this.getClass()
);
} catch (ClassCastException cce) {
valid = false;
}
if (!valid) {
String name = this.getClass().getSimpleName();
throw new IllegalImplementationException(
name + " must be declared as "+ "\"class " + name + " extends Foo<"+name+">\"");
}
}
private static class IllegalImplementationException extends RuntimeException {
IllegalImplementationException(String message) {
super(message);
}
}
}
在 C# 中更简单:
public class Foo<T> where T : Foo<T> {
public List<T> container;
protected Foo() {
enforceConstraints();
}
private void enforceConstraints() {
if (!this.GetType().Equals(typeof(T))) {
String name = this.GetType().Name;
throw new IllegalImplementationException(
name + " must be declared as " + "\"class " + name + " : Foo<" + name + ">\"");
}
}
}
public class IllegalImplementationException : Exception {
public IllegalImplementationException(String message) : base(message) {}
}
enforceConstraints()
可以在发送到生产环境时删除。请注意,这会强制通过反射以我们的方式限制泛型参数,因为此处所需的类型限制在 Java 或 C# 中不可用。因为我们完全通过反射来强制执行约束,所以没有必要添加约束 T extends Foo<T>
,但这可以防止误用。请注意,使用约束 Foo<T extends Foo<T>
,您可以有 Bar1 extends Foo<Bar1>
和 Bar2 extends Foo<Bar1>
,但我们不想要第二种类型,因此为什么需要反射。