【问题标题】:Swap two variables without using ref/out in C#在 C# 中不使用 ref/out 交换两个变量
【发布时间】:2010-10-08 04:35:12
【问题描述】:

是否可以在不使用 C# 中的 ref/out 关键字的情况下交换两个变量(即使用 unsafe)?

例如,

        swap(ref x,ref y);//It is possbile to by passing the reference

但是,有没有其他方法可以做同样的事情。在交换函数中,您可以使用临时变量。但是,如何在不使用 C# 中的 ref/out 关键字的情况下交换变量?

【问题讨论】:

    标签: c# keyword swap


    【解决方案1】:

    一个(非常!)使用委托的人为示例:

    class Program
    {
        static void FunkySwap<T>(T a, T b, Action<T> setA, Action<T> setB)
        {
            T tempA = a;
            setA(b);
            setB(tempA);
        }
        static void Main(string[] args)
        {
            string s1 = "big";
            string s2 = "apples";
            Console.WriteLine("BEFORE, s1: {0}, s2: {1}", s1, s2);
            FunkySwap(s1, s2, a => s1 = a, b => s2 = b);
            Console.WriteLine("AFTER,  s1: {0}, s2: {1}", s1, s2);
        }
    }
    

    虽然上述内容非常愚蠢,但在其他情况下使用委托设置器方法可能很有用;我已经使用该技术来实现属性修改的撤消/重做。

    【讨论】:

    • 这很好(嗯,这很可怕,但作为一个答案很好),因为我们不能在没有 ref 的情况下传递变量,或者用指针或对象包含伪造 ref,你传入代替功能!良好的横向思维。
    • 尽管看起来一点也不像,但这是 Michael Shimmins 答案的副本。
    • @Ben Voigt:怎么会这样?他分配了一个新结构,我的使用委托并更改原始引用。
    • 啊,你是对的,返回一个结构不是那么相似。但是,您使用闭包与将要交换的值放入类实例中,调用函数以交换成员,然后从类实例中读取它们完全相同,因为 MSIL 代码实际上就是这样做的。跨度>
    • @Ben Voigt:嗯,生成的 MSIL 代码有很大的不同——但你说得对,有相当多的开销在 C# 代码中是不可见的。在每个调用站点,我们构造了两个 Action 对象,FunkySwap() 执行了两个虚拟方法调用。 Swapable 解决方案的调用站点要短得多,分配一个新对象,并且只在 Swap() 中进行简单的字段加载/存储:)
    【解决方案2】:

    不,如果没有使用refout 传递引用,就不可能影响调用者中的变量*。你可以影响班级成员,但你怎么知道你被要求交换哪些成员?

    *(您可以影响引用类型的实例,并且更改将对调用者可见,但实例不是“变量”。)

    【讨论】:

    • 好吧,他是在问是否可以使用 unsafe
    • @Rune:您只是在不使用ref 关键字的情况下创建了一个传递引用参数。这确实符合问题的本质,我只是想知道它是否符合精神。
    【解决方案3】:

    使用元组

    int a = 4, b = 8;
    (a, b) = (b, a);
    

    【讨论】:

      【解决方案4】:

      不是真的,除非您对ref 的唯一问题是不喜欢这个词本身。

      您可以通过指针交换,例如:

      public unsafe void Swap(int* x, int* y)
      {
          unsafe
          {//lets not use a temp, just to be different!
              *x ^= *y;
              *y ^= *x;
              *x ^= *y;
          }
      }
      

      但实际上,唯一实际的区别是引用可以让您避免的所有指针陷阱,以及它必须是不安全的事实。它基本上是在做同样的事情。

      【讨论】:

        【解决方案5】:

        我试过了

        class Program
        {
            static void Main(string[] args)
            {
                int x = 3;
                int y = 6;
                Console.Write(string.Format("before swap x={0} y={1}", x, y));
                Swap(x, y);
                Console.Write(string.Format("after swap x={0} y={1}", x, y));
                Console.ReadKey();
            }
        
            static public unsafe void Swap(int a, int b)
            {
                int* ptrToA = &a;
                int* ptrToB = &b;
                int c = a;
                *ptrToB = c;
                *ptrToB = *ptrToA;
            }
        }
        

        并且完全忘记了ints 是按值传递的,而且我无法将实际上从调用者复制到被调用者堆栈的东西的指针。

        所以它不起作用

        看来,我并没有变得更聪明,而是浪费了一些时间,但无论如何还是想与您分享:)

        【讨论】:

          【解决方案6】:

          您可以传递对象中的值并返回该对象的一个​​实例,并交换了值:

          public struct Swapable
          {
              public int A;
              public int B;
          }
          
          public Swapable Swap(Swapable swapable)
          {
              return new Swapable()
              {
                  A = swapable.B;
                  B = swapable.A;
              };
          }
          

          【讨论】:

            【解决方案7】:

            我尝试过使用 unsafe 并且它有效,请参阅代码

            namespace ConsoleApplication2
            {
            class myclass
            {
                public unsafe void swap(int *x, int *y)
                {
                    unsafe
                    {
                        int temp = 0;
                        temp = *x;
                        *x = *y;
                        *y = temp;
                        Console.WriteLine("Using Swap1");
                        Console.WriteLine("x:"+*x);
                        Console.WriteLine("y:" + *y);
                    }
                }
            }
            
            class Program
            {
                static void Main(string[] args)
                {
                    unsafe
                    {
                        int x = 10;
                        int y = 20;
                        int* t1 = &x;
                        int* t2 = &y;
                        myclass m1 = new myclass();
                        m1.swap(t1,t2);
                        Console.WriteLine("Main");
                        Console.WriteLine("x: " + x);
                        Console.WriteLine("y: " + y);
                        Console.ReadLine();
            
                    }
                }
            }
            

            }

            【讨论】:

              【解决方案8】:

              这里我将对象作为参数传递

              class person1
                          {
                              public int x, y;
                              public person1(int x,int y)
                                  {
                                  this.x = x;
                                  this.y = y;
              
                                  }
                              public void changes(person1 p1)
                              {
                                 // int t;
                                  this.x = x + y;  //x=30 x=10,y=20
                                  this.y = x - y;  //y=30-20=10
                                  this.x = x - y; //x=30-10=20
                              }
                  }
                   static void Main(string[] args)
                     {
                           person1 p1 = new person1(10,20);
                           p1.changes(p1);
                           Console.WriteLine("swapp hoge kya ?x={0} and y={1}", p1.x, p1.y);
                           Console.ReadKey();
                    }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2017-11-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-05-24
                • 2013-04-18
                • 2011-10-02
                相关资源
                最近更新 更多