在c#

时间:2019-02-21 01:57:15

标签: c#

最近,我遇到了一个问题,即使用扩展方法时如何更改“ 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参数。

深深地感谢我的老师。

2 个答案:

答案 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);
    }
}

IDEOne Code

结果

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);