这取决于...您特别说您不想要泛型类...唯一的其他选择是非泛型类中的泛型方法。你可以让编译器发出调用的唯一其他时间是如果你调用,或(from ) on a ,因为那些是 then - 如果有 an它们将是;如果它没有,它们将是。这就是为什么您应该始终使用这 3 个;p 但我离题了。一个简单的例子是具有一些静态方法的实用程序类 -扩展constrained
ToString()
GetHashCode()
Equals()
object
struct
constrained
struct
override
call
override
callvirt
override
struct
方法将是一个理想的示例,因为您还可以获得编译器将在公共/隐式 API 和扩展/显式 API 之间自动切换的优势,而您无需更改代码。例如,以下(显示隐式和显式实现)没有装箱,只有一个call
和一个constrained
+ callvirt
,它将通过call
JIT 实现:
using System;
interface IFoo
{
void Bar();
}
struct ExplicitImpl : IFoo
{
void IFoo.Bar() { Console.WriteLine("ExplicitImpl"); }
}
struct ImplicitImpl : IFoo
{
public void Bar() {Console.WriteLine("ImplicitImpl");}
}
static class FooExtensions
{
public static void Bar<T>(this T foo) where T : IFoo
{
foo.Bar();
}
}
static class Program
{
static void Main()
{
var expl = new ExplicitImpl();
expl.Bar(); // via extension method
var impl = new ImplicitImpl();
impl.Bar(); // direct
}
}
这是 IL 的关键部分:
.method private hidebysig static void Main() cil managed
{
.entrypoint
.maxstack 1
.locals init (
[0] valuetype ExplicitImpl expl,
[1] valuetype ImplicitImpl impl)
L_0000: ldloca.s expl
L_0002: initobj ExplicitImpl
L_0008: ldloc.0
L_0009: call void FooExtensions::Bar<valuetype ExplicitImpl>(!!0)
L_000e: ldloca.s impl
L_0010: initobj ImplicitImpl
L_0016: ldloca.s impl
L_0018: call instance void ImplicitImpl::Bar()
L_001d: ret
}
.method public hidebysig static void Bar<(IFoo) T>(!!T foo) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.ExtensionAttribute::.ctor()
.maxstack 8
L_0000: ldarga.s foo
L_0002: constrained. !!T
L_0008: callvirt instance void IFoo::Bar()
L_000d: ret
}
然而,扩展方法的一个缺点是它在堆栈上做一个额外的副本(struct
参见反正)。如果是这种情况,参数会很有帮助,但请注意扩展方法不能有参数 - 所以你不能使用扩展方法来做到这一点。但请考虑:ldloc.0
ref
ref this
Bar(ref expl);
Bar(ref impl);
和:
static void Bar<T>(ref T foo) where T : IFoo
{
foo.Bar();
}
这是:
L_001d: ldloca.s expl
L_001f: call void Program::Bar<valuetype ExplicitImpl>(!!0&)
L_0024: ldloca.s impl
L_0026: call void Program::Bar<valuetype ImplicitImpl>(!!0&)
和:
.method private hidebysig static void Bar<(IFoo) T>(!!T& foo) cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: constrained. !!T
L_0007: callvirt instance void IFoo::Bar()
L_000c: ret
}
仍然没有装箱,但现在我们也从不复制结构,即使是显式情况。