将值参数委托给接受ref参数的函数
本文关键字:参数 ref 函数 值参 | 更新日期: 2023-09-27 18:16:59
为了减少我正在开发的库的维护,我试图将类似的功能委托给单个函数。举个例子,假设有一个双组件向量,其中Add函数接受by-ref参数,而其他函数接受by-value参数。我们的想法是简单地在by-value函数中调用by-ref函数,这样就只需要维护by-ref函数。
。
struct Vector2
{
public float X;
public float Y;
public Vector2(float x, float y)
{
this.X = x;
this.Y = y;
}
public static void Add(ref Vector2 a, ref Vector2 b, out Vector2 result)
{
result.X = a.X + b.X;
result.Y = a.Y + b.Y;
}
public static Vector2 Add1(Vector2 a, Vector2 b)
{
Add(ref a, ref b, out a);
return a;
}
public static Vector2 Add2(Vector2 a, Vector2 b)
{
a.X += b.X;
a.Y += b.Y;
return a;
}
}
问题是by-ref重载函数没有内联,导致我认为是较慢的代码(不包括nops)。
启用JIT优化的发布输出:
Add1:
Add(ref a, ref b, out a);
0000002b lea eax,[ebp+10h]
0000002e push eax
0000002f lea ecx,[ebp+10h]
00000032 lea edx,[ebp+8]
00000035 call FFEDA508
0000003a nop
return a;
0000003b lea edi,[ebp-44h]
0000003e lea esi,[ebp+10h]
00000041 movq xmm0,mmword ptr [esi]
00000045 movq mmword ptr [edi],xmm0
00000049 nop
0000004a jmp 0000004C
Add2:
a.X += b.X;
0000002b fld dword ptr [ebp+8]
0000002e fadd dword ptr [ebp+10h]
00000031 fstp dword ptr [ebp+10h]
a.Y += b.Y;
00000034 lea eax,[ebp+8]
00000037 fld dword ptr [eax+4]
0000003a lea eax,[ebp+10h]
0000003d fadd dword ptr [eax+4]
00000040 fstp dword ptr [eax+4]
return a;
00000043 lea edi,[ebp-44h]
00000046 lea esi,[ebp+10h]
00000049 movq xmm0,mmword ptr [esi]
0000004d movq mmword ptr [edi],xmm0
00000051 nop
00000052 jmp 00000054
是否有一种方法可以使Add调用内联?
请注意,该库需要。net 4.0,这意味着激进内联是不可用的。
尝试启用主动内联:
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add(ref Vector2 a, ref Vector2 b, out Vector2 result)
{
result.X = a.X + b.X;
result.Y = a.Y + b.Y;
}
提示编译器(或JIT)内联该函数。
注意:AggressiveInlining
在。net 4.5中是新的。
我大胆猜测一下,你可能是一个c++程序员。你在这里使用的ref
和out
关键字是完全超流畅的。您可以删除它们,您的代码将正常运行。
事实上,我没有看到任何功能,一个简单的版本不会提供:
public Vector2 Add(Vector2 other)
{
return new Vector2() { X = this.X + other.X, Y = this.Y + other.Y };
}
即使你想保持你的API静态,删除所有的ref
和out
关键字,他们不是你的代码所必需的。
我刚刚注意到你正在使用结构体(值类型),所以我之前写的是不正确的,我删除了我的帖子。然后我又想了想:要么你想让它成为一个值类型,因为它太小了,复制速度足够快,要么你不想。你使它成为一个值类型,现在你正试图通过滥用ref
和out
关键字来解决你自己的决定。
public static void Add(ref Vector2 a, ref Vector2 b, out Vector2 result)
这很容易是
public static void Add(Vector2 a, Vector2 b, ref Vector2 result)
如果你想要按引用传递,为什么不把它作为一个引用类型呢?如果你这样做,那么我上面写的所有内容仍然有效:)
我将咬牙咬牙,手动内联不能自动完成内联且调用指令很重要的代码,例如Add1这样的函数。在这种情况下,自动化单元测试可以处理问题检测,因此维护噩梦不是一个大问题。
感谢SO人的帮助