什么时候使用C#ref关键字一个好主意?

时间:2010-08-21 22:20:20

标签: c# .net parameters interface

我在生产代码中看到的参数越多,我遇到的误用就越多,它给我带来的痛苦就越大。我讨厌这个关键字,因为从框架构建的角度来看,这似乎很愚蠢。何时向代码用户传达可能从其下方更改对象引用/值的概念何时是一个好主意?

相比之下,我喜欢关键词,在没有使用任何关键词的情况下我更喜欢这两种情况,因为在使用它们时给予了保证。另一方面,Ref不能保证,除非你在传入参数之前被迫初始化参数,即使它没有任何改变。

我不是圣人开发者;我确信它有实际适用的用途。我只想知道它们是什么。

10 个答案:

答案 0 :(得分:31)

框架设计指南(Krzysztof Cwalina和Brad Abrams的一本书)建议避免使用refout参数。

  使用outref参数

避免

     

使用outref参数需要使用指针,理解值类型和引用类型的不同,以及处理具有多个返回值的方法。此外,outref参数之间的差异尚未被广泛理解。为普通受众设计的框架架构师不应期望用户掌握使用outref参数。

框架设计指南引用规范Swap方法作为有效例外:

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

但同时发表评论意见

  

Swap总是出现在这些讨论中,但是我从未编写过大学以来实际需要交换方法的代码。除非你有充分的理由,否则完全避免outref

答案 1 :(得分:13)

大多数Interlocked methods使用ref参数(我确定您同意)这是个充分的理由。

答案 2 :(得分:10)

我试图在公共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是私有方法的地方,只是搬出来保持方法责任可管理。

答案 3 :(得分:4)

任何时候你想要改变类型的值 - 如果你想有效地更新一对相关值(即返回一个包含两个int的结构),这种情况会发生很多,你传递(ref int x,ref int y))

答案 4 :(得分:2)

也许当你有一个结构(它是一个值类型)时:

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的方法进行成像,然后使用outref获得两倍的参数。另一种方法是返回N元组。我没有关于何时使用这些东西的真实例子。

添加:如果.TryParse方法返回out而不是Nullable<T>,那么这些方法也可以避免boolean * T。{{1}}基本上是{{1}}的元组。

答案 5 :(得分:0)

当您需要在bignums上使用高效的就地算法时,它非常有用。

答案 6 :(得分:0)

假设我猜你可能会使用很多ref / out参数,如果你打算模仿旧程序软件的架构,比如老式游戏引擎等等。我已经扫描了一个源代码,我认为它是Duke Nukem 3D,并且它是程序化的,有很多子程序修改变量,几乎没有函数。显然,除非你有一些特定的目标,否则你不太可能为这个真实的制作应用程序编程。

答案 7 :(得分:0)

如果有人希望将数组传递给可能会或可能不会改变其大小并对其执行其他操作的函数。通常,人们会将数组包装在另一个对象中,但如果希望直接通过引用处理数组,那么这似乎是最自然的方法。

答案 8 :(得分:-1)

我经常使用ref。想想具有多个返回值的函数。 创建返回对象(辅助对象)或甚至为此目的使用哈希表是没有意义的。

示例:

 getTreeNodeValues(ref selectedValue, ref selectedText);

编辑:

最好在这里使用 - 如评论。

 getTreeNodeValues(out selectedValue, out selectedText);

我用它来处理对象:

MyCar car = new MyCar { Name="TestCar"; Wieght=1000; }

UpdateWeight(ref car, 2000);

答案 9 :(得分:-1)

除了swap&lt;&gt;之外的另一个有用示例是这样的:

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


}

在这里使用它不是一个选项