使用 Java 和 C# 的泛型来模拟鸭子类型
Using Java and C#'s generics to simulate duck typing
http://nullprogram.com/blog/2014/04/01/ 试图用一个例子来解释 Java 的泛型不能模拟鸭子类型:
class Caller<T> {
final T callee;
Caller(T callee) {
this.callee = callee;
}
public void go() {
callee.call(); // compiler error: cannot find symbol call
}
}
class Foo {
public void call() { System.out.print("Foo"); }
}
class Bar {
public void call() { System.out.print("Bar"); }
}
public class Main {
public static void main(String args[]) {
Caller<Foo> f = new Caller<>(new Foo());
Caller<Bar> b = new Caller<>(new Bar());
f.go();
b.go();
System.out.println();
}
}
The program will fail with a compile-time error. This is the result of
type erasure. Unlike C++’s templates, there will only ever be one
compiled version of Caller
, and T
will become Object
. Since Object
has
no call()
method, compilation fails.
是否意味着通过Java泛型,类型参数的方法仅限于classjava.lang.Object
的方法?
C# 的泛型是根据具体化而不是类型擦除来实现的。 C#的泛型没有Java的泛型有上述限制吗?那么 C# 的泛型真的可以实现与 duck typing 相同的功能吗?
谢谢。
C# 具有相同的限制。
除了 dynamic
,C# 在任何地方都没有任意的 ducky-typing;即使使用泛型,您也只能调用由类型定义的方法(具体来说,泛型类型参数的约束,默认为 object
)。
can C#'s generics actually achieve the same thing as duck typing?
没有。但是 C# 的泛型可以包含一个约束,其中类型参数被限制为继承或实现某些特定类型。完成后,该类型参数类型的任何表达式都将解析为约束类型,并且可以访问该类型的成员。
这类似于您阅读的文章中描述的 extends
约束。
C# 中唯一的鸭子类型支持是 dynamic
关键字,其中涉及 dynamic
值的表达式的最终编译被推迟到实际运行时类型已知的运行时。
相关阅读:
Trivial C# class with a generic parameter wouldn't compile for no apparent reason
Call a method of type parameter
Does it mean that by Java generics, the methods of a type parameter are limited to the methods of class java.lang.Object?
不完全是。虽然大多数泛型都被删除了,但可以在 Java 中包含一个约束,这样类型参数必须是特定类型。这实际上使它不是 Object
.
未经测试,但这应该很接近。
class Caller<T extends CallMe> {
final T callee;
Caller(T callee) {
this.callee = callee;
}
public void go() {
callee.call(); // should work now
}
}
interface CallMe {
void call();
}
class Foo implements CallMe {
public void call() { System.out.print("Foo"); }
}
class Bar implements CallMe {
public void call() { System.out.print("Bar"); }
}
public class Main {
public static void main(String args[]) {
Caller<Foo> f = new Caller<>(new Foo());
Caller<Bar> b = new Caller<>(new Bar());
f.go();
b.go();
System.out.println();
}
}
http://nullprogram.com/blog/2014/04/01/ 试图用一个例子来解释 Java 的泛型不能模拟鸭子类型:
class Caller<T> { final T callee; Caller(T callee) { this.callee = callee; } public void go() { callee.call(); // compiler error: cannot find symbol call } } class Foo { public void call() { System.out.print("Foo"); } } class Bar { public void call() { System.out.print("Bar"); } } public class Main { public static void main(String args[]) { Caller<Foo> f = new Caller<>(new Foo()); Caller<Bar> b = new Caller<>(new Bar()); f.go(); b.go(); System.out.println(); } }
The program will fail with a compile-time error. This is the result of type erasure. Unlike C++’s templates, there will only ever be one compiled version of
Caller
, andT
will becomeObject
. SinceObject
has nocall()
method, compilation fails.
是否意味着通过Java泛型,类型参数的方法仅限于classjava.lang.Object
的方法?
C# 的泛型是根据具体化而不是类型擦除来实现的。 C#的泛型没有Java的泛型有上述限制吗?那么 C# 的泛型真的可以实现与 duck typing 相同的功能吗?
谢谢。
C# 具有相同的限制。
除了 dynamic
,C# 在任何地方都没有任意的 ducky-typing;即使使用泛型,您也只能调用由类型定义的方法(具体来说,泛型类型参数的约束,默认为 object
)。
can C#'s generics actually achieve the same thing as duck typing?
没有。但是 C# 的泛型可以包含一个约束,其中类型参数被限制为继承或实现某些特定类型。完成后,该类型参数类型的任何表达式都将解析为约束类型,并且可以访问该类型的成员。
这类似于您阅读的文章中描述的 extends
约束。
C# 中唯一的鸭子类型支持是 dynamic
关键字,其中涉及 dynamic
值的表达式的最终编译被推迟到实际运行时类型已知的运行时。
相关阅读:
Trivial C# class with a generic parameter wouldn't compile for no apparent reason
Call a method of type parameter
Does it mean that by Java generics, the methods of a type parameter are limited to the methods of class java.lang.Object?
不完全是。虽然大多数泛型都被删除了,但可以在 Java 中包含一个约束,这样类型参数必须是特定类型。这实际上使它不是 Object
.
未经测试,但这应该很接近。
class Caller<T extends CallMe> {
final T callee;
Caller(T callee) {
this.callee = callee;
}
public void go() {
callee.call(); // should work now
}
}
interface CallMe {
void call();
}
class Foo implements CallMe {
public void call() { System.out.print("Foo"); }
}
class Bar implements CallMe {
public void call() { System.out.print("Bar"); }
}
public class Main {
public static void main(String args[]) {
Caller<Foo> f = new Caller<>(new Foo());
Caller<Bar> b = new Caller<>(new Bar());
f.go();
b.go();
System.out.println();
}
}