最近,我遇到了一个问题,即使用扩展方法时如何更改“ int”值,不允许使用关键字“ ref”或“ out”:
static void Main(string[] args)
{
var a = 5;
var b = 6;
a.Swap(b);
Console.WriteLine("a={0},b={1}", a, b);
Console.ReadKey();
}
我想实现Swap方法(交换变量a和变量b)和最终输出,如下所示:
a = 6,b = 5
交换方法需要交换变量a和变量b,该问题由我的老师分配。
我的答案是:
unsafe static void Swap(this int a, int b)
{
int* pb = &b;
pb += 7;
int* pa = &a;
pa += 8;
int temp = *pa;
*pa = *pb;
*pb = temp;
}
但是我的老师说这还不够好。因为7和8会受到C#编译器的影响。
我真的不知道如何实现Swap方法。我认为整数将在传递给Swap时按值传递,除非找到其原始地址,否则无法更改它。
我误会了吗?您的想法将不胜感激。
已添加:
很多人说这没有道理,很多问题我都知道这没有道理。但这确实可以做到。从老师那里得到答案后,我将答案粘贴到波纹管中。
添加了20190225
我从老师那里得到了答案,下面是完整答案:
internal static class Program
{
static void Main(string[] args)
{
var (a, b) = (5,6);
a.Swap(b);
Console.WriteLine($"a=({a}),b=({b})");
Console.ReadKey();
}
private static void Swap<T>(ref this T op1, in T op2)
where T : struct
{
var temp = op1;
op1 = op2;
RefUnlocker.Unlock(op2) = temp;
}
}
public class RefUnlocker
{
private delegate ref T InToRef<T>(in T arg) where T : struct;
private static ref T RefWrapper<T>(ref T arg) where T : struct => ref arg;
private static readonly MethodInfo _refWrapper = typeof(RefUnlocker)
.GetMethod(nameof(RefWrapper), BindingFlags.Static | BindingFlags.NonPublic);
public static ref T Unlock<T>(in T arg) where T : struct
{
Delegate dgt = Delegate.CreateDelegate(typeof(InToRef<T>), _refWrapper.MakeGenericMethod(typeof(T)));
InToRef<T> itrf = (InToRef<T>)dgt;
return ref itrf(arg);
}
}
C#7.2提供了关键字in。参数上的in修饰符,用于指定参数是通过引用传递的,而不是被调用方法修改的。在参数中添加in修饰符是与源兼容的更改。
但是,您可以使用Delegate修改in参数。
深深地感谢我的老师。
答案 0 :(得分:3)
目前还不清楚为什么要在某些指针上加上7和8。 您希望达到什么目的?
如果扩展方法不是必需的,那么答案很简单!! 正如迈克尔·兰德尔(Michael Randall)写道:
static unsafe void Swap(int* pa, int* pb)
{
int temp = *pb;
*pb = *pa;
*pa = temp;
}
// Call this with: Swap(&a,&b);
using System;
public static class Test
{
static unsafe void Swap(this int a, int* pa, int* pb)
{
*pa = *pb;
*pb = a;
}
public static unsafe void Main()
{
var a = 5;
var b = 6;
a.Swap(&a, &b);
Console.WriteLine("a={0},b={1}", a, b);
}
}
Success #stdin #stdout 0.01s 131520KB
a=6,b=5
答案 1 :(得分:2)
这仅是备份@abelenky's的答案,而不是本身的答案
只有指针,没有扩展名,没有ref
,没有out
public unsafe static void Swap(int* a, int* b)
{
var temp = *a;
*a = *b;
*b = temp;
}
用法
public unsafe static void Main()
{
var a = 5;
var b = 6;
Swap(&a, &b);
Console.WriteLine("a={0},b={1}", a, b);
Console.ReadKey();
}
或带有franken扩展名的另一个变体
public static unsafe class ext
{
public static int Swap(this int a, int* b)
{
var temp = *b;
*b = a;
return temp;
}
}
用法
var a = 5;
var b = 6;
a = a.Swap(&b);
Console.WriteLine("a={0},b={1}", a, b);