代码之家  ›  专栏  ›  技术社区  ›  bwerks

什么时候使用c ref关键字是个好主意?

  •  29
  • bwerks  · 技术社区  · 14 年前

    我在生产代码中看到的ref越多,我遇到的误用就越多,它给我带来的痛苦也就越大。我开始讨厌这个关键字,因为从框架构建的角度来看,它看起来很愚蠢。什么时候向代码的用户传达 也许吧 是否从下面更改对象引用/值?

    相比之下,我更喜欢没有关键词的关键词,在这两种情况下,这都是因为在使用关键词的时候你得到了保证。另一方面,ref不作任何保证,除非在传入参数之前必须对其进行初始化,即使不会对其进行任何更改。

    不过,我不是Sage开发人员;我相信它有实际应用的用途。我只想知道它们是什么。

    10 回复  |  直到 10 年前
        1
  •  31
  •   Timwi    14 年前

    这个 框架设计指南 (一本由KrzysztofCvalina和BradAbrams写的书)建议避免 ref out 参数。

    避免 使用 外面的 裁判 参数。

    使用 外面的 裁判 参数需要有指针方面的经验,了解值类型和引用类型的区别,以及处理具有多个返回值的方法。另外,两者之间的区别 外面的 裁判 参数并没有被广泛理解。为普通用户设计的框架架构师不应该期望用户掌握 外面的 裁判 参数。

    框架设计指南引用了规范 Swap 方法作为有效异常:

    void Swap<T>(ref T obj1, ref T obj2)
    {
        T temp = obj1;
        obj1 = obj2;
        obj2 = temp;
    }
    

    但同时也有评论评论

    在这些讨论中总是会出现交换,但是我从大学开始就没有编写真正需要交换方法的代码。除非你有充分的理由,否则避免 外面的 裁判 总而言之。

        2
  •  13
  •   Timwi    14 年前

    大部分的 Interlocked methods 使用 ref 参数(我相信你同意)是有充分理由的。

        3
  •  10
  •   Marc Gravell    14 年前

    我尽量避免在公共API上使用它,但它确实有用途。可变值类型是一个重要的类型,特别是在像CF这样的东西上(由于平台的需求,可变结构更常见)。然而,我使用它的最常见时间可能是将复杂算法的某些部分重构为几个方法时,其中一个状态对象被过度杀戮,我需要传递多个值:

    var x = .....
    var y = .....
    // some local code...
    var z = DoSomethingSpecific(ref x, ref y); // needs and updates x/y
    // more local code...
    

    等在哪里 DoSomethingSpecific 是一种私人方法,只是为了保持方法责任的可控性。

        4
  •  4
  •   Jason Williams    14 年前

    随时更改 价值 类型-在希望有效地更新一对相关值(即,不返回包含两个int的结构,而是传递(ref int x,ref int y))的情况下,会发生很多这种情况。

        5
  •  2
  •   Lasse Espeholt    14 年前

    可能当您有一个结构(它是一个值类型)时:

    struct Foo
    {
        int i;
    
        public void Test()
        {
            i++;
        }
    }
    
    static void update(ref Foo foo)
    {
        foo.Test();
    }
    

    Foo b = new Foo();
    update(ref b);
    

    这里您将使用两个参数 out 像:

    static void update(Foo foo, out Foo outFoo) //Yes I know you could return one foo instead of a out but look below
    {
        foo.Test();
    
        outFoo = foo;
    }
    

    成像具有一个以上的方法 Foo 然后你会得到两倍的参数 外面的 对战 ref . 另一种方法是返回n元组。我没有一个真实的例子来说明什么时候使用这些东西。

    附加项: 不同 .TryParse 方法也可以避免 外面的 如果他们回来了 Nullable<T> 相反,它本质上是 boolean * T .

        6
  •  0
  •   Charles    14 年前

    当你需要在Bignums上使用高效的就地算法时,它是有用的。

        7
  •  0
  •   Tom W    14 年前

    假设地说,如果你打算模仿旧程序软件的体系结构,比如旧的游戏引擎等等,我猜你可能会使用很多的ref/out参数。我已经扫描了其中一个的源代码,我认为它是Duke Nukem 3D,它是程序化的,有很多子程序在适当的地方修改变量,几乎没有函数。显然,除非您有特定的目标,否则您不太可能为实际的生产应用程序编写这样的程序。

        8
  •  0
  •   supercat    14 年前

    如果一个人想要将数组传递给一个函数,这个函数可能会改变它的大小,也可能不会对它做其他的事情,那该怎么办呢?通常,我们会将数组包装在另一个对象中,但如果希望处理直接通过引用传递的数组,则似乎是最自然的方法。

        9
  •  -1
  •   Andreas Rehm    14 年前

    我经常使用REF。只需考虑具有多个返回值的函数。 创建返回对象(helper对象)甚至为此使用哈希表都没有意义。

    例子:

     getTreeNodeValues(ref selectedValue, ref selectedText);
    

    编辑:

    最好在这里使用——正如评论中所说。

     getTreeNodeValues(out selectedValue, out selectedText);
    

    我用它来处理对象:

    MyCar car = new MyCar { Name="TestCar"; Wieght=1000; }
    
    UpdateWeight(ref car, 2000);
    
        10
  •  -1
  •   boctulus    10 年前

    除了掉期之外,另一个有用的例子是:

    Prompter.getString("Name ? ", ref firstName);
    Prompter.getString("Lastname ? ", ref lastName);
    Prompter.getString("Birthday ? ", ref firstName);
    Prompter.getInt("Id ? ", ref id);
    Prompter.getChar("Id type: <n = national id, p = passport, d = driver licence, m = medicare> \n? ", ref c);
    
    
    
    public static class Prompter
    {
        public static void getKey(string msg, ref string key)
        {
            Console.Write(msg);
            ConsoleKeyInfo cki = Console.ReadKey();
            string k = cki.Key.ToString();
            if (k.Length == 1)
                key = k;
        }
    
        public static void getChar(string msg, ref char key)
        {
            Console.Write(msg);
            key = Console.ReadKey().KeyChar;
            Console.WriteLine();
        }
    
        public static void getString(string msg, ref string s)
        {
            Console.Write(msg);
            string input = Console.ReadLine();
            if (input.Length != 0)
                s = input;
        }
    
        public static void getInt(string msg, ref int i)
        {
            int result;
            string s;
    
            Console.Write(msg);
            s = Console.ReadLine();
    
            int.TryParse(s, out result);
            if (result != 0)
                i = result;       
        }
    
        // not implemented yet
        public static string getDate(string msg)
        {
            // I should use DateTime.ParseExact(dateString, format, provider);
            throw new NotImplementedException();
        }    
    
    
    }
    

    在外面使用,这不是一个选择