16

我想知道对于值类型是否有任何可能的方式......

public static class ExtensionMethods {
    public static void SetTo(this Boolean source, params Boolean[] bools) {
        for (int i = 0; i < bools.Length; i++) {
            bools[i] = source;
        }
    }
}

那么这是可能的:

Boolean a = true, b, c = true, d = true, e;
b.SetTo(a, c, d, e);

当然,这不起作用,因为 bool 是值类型,因此它们作为值而不是引用传递给函数。

除了将值类型包装成引用类型(通过创建另一个类)之外,还有什么方法可以在使用 params 修饰符时通过引用(ref)将变量传递给函数?

4

5 回答 5

23

这是不可能的。为了解释原因,首先阅读我关于为什么我们通过将值类型的局部变量放入堆栈来优化释放它们的文章:

https://web.archive.org/web/20100224071314/http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two。 aspx

现在您了解了这一点,应该清楚为什么不能将“ref bool”存储在数组中。如果可以,那么您可以拥有一个比被引用的堆栈变量存活时间更长的数组。我们有两个选择:要么允许这样做,如果你弄错了,程序会崩溃和死机——这是 C 的设计者做出的选择。安全的。我们选择了后者。

但是,让我们更深入地考虑一下这个问题。如果你想要传递“允许我设置变量的东西”,我们就有. 这只是一个代表:

static void DoStuff<T>(this T thing, params Action<T>[] actions)
{
    foreach(var action in actions) action(thing);
}
...
bool b = whatever;
b.DoStuff(x=>{q = x;}, x=>{r = x;} );

有道理?

于 2009-11-21T18:43:25.997 回答
3

不幸的是,Java 社区以及现在的 .NET 开发人员认为,以“安全”为名的灵活性较低是首选解决方案,并且要以更少的代码行实现相同的结果,您必须选择非常复杂的(所有这些类结构,代表等)。

在德尔福我可以简单地做这样的事情:

var
  a: integer; f: double; n: integer;
sscanf(fmtstr, valuestr, [@a, @f, @n]);

//<-- “sscanf”是我自己编写的一个函数,它接受一个开放的指针数组。

在 C# 中,您必须执行以下操作:

int a; double f; int n;
object [] o = new object[];
sscanf(fmtstr, valuestr, ref o);
a = o[0];
f = o[1];
n = o[2];

那是 5 行代码来完成我在 1 行 Delphi 代码中可以做的事情。我认为某处有一个公式,代码中出现错误的可能性随着代码行数的增加而呈几何级数增加;因此,如果您有 20 行代码,那么您的代码出现错误的可能性是 10 行代码的 4 倍。

当然,你可以通过使用带有所有那些奇怪的尖括号和奇怪的语法的委托来减少你的代码行数,但我认为这也是错误的避风港。

于 2012-12-10T15:28:35.943 回答
2

真的没有办法。你可以这样做:

public static void Main(string[] args)
{
    BooleanWrapper a = true, b = true, c = true, d = true, e = new BooleanWrapper();
    b.SetTo(a, c, d, e);
}

public static void SetTo(this BooleanWrapper sourceWrapper, params BooleanWrapper[] wrappers)
{
    foreach (var w in wrappers)
        w.Value = sourceWrapper.Value;
}

public class BooleanWrapper
{
    public BooleanWrapper() { }

    public BooleanWrapper(Boolean value)
    {
        Value = value;
    }

    public Boolean Value { get; set; }

    public static implicit operator BooleanWrapper(Boolean value)
    {
        return new BooleanWrapper(value);
    }
}

但是话又说回来,这有什么比这样做更好的:

public static void Main(string[] args)
{
    Boolean[] bools = new Boolean[5];
    bools.SetTo(bools[1]); // Note I changed the order of arguments. I think this makes more sense.
}

public static void SetTo(this Boolean[] bools, Boolean value)
{
    for(int i = 0; i < bools.Length; i++)
        bools[i] = value;
}

毕竟,数组一系列变量。如果您需要一些行为类似于变量序列的东西,请使用数组。

于 2009-11-21T17:12:29.423 回答
1

这是一些有趣的解决方案:

public delegate RecursionRefFunc<T> RecursionRefFunc<T>(ref T arg);

public static RecursionRefFunc<T> Boo<T>(ref T input)
{
    Console.WriteLine(input); // Work in here
    return Boo;
}

public static void Main(string[] args)
{
    int x1 = 1, x2 = 2, x3 = 3, x4 = 4, x5 = 5;
    Boo(ref x1)(ref x2)(ref x3)(ref x4)(ref x5);
}

// Output: //
// 1
// 2
// 3
// 4
// 5

委托可以递归声明。

在外面返回一个函数并再次调用。

你会被代码审查者杀死。


OW<: CWKSC/MyLib_Csharp

于 2020-05-23T16:43:08.457 回答
0

bool即使s 是引用类型,这也是不可能的。虽然 aclass是引用类型,但里面的变量Boolean[]仍然是value,只是value引用。分配引用的值只会更改该特定变量的值。变量数组的概念ref没有意义(因为数组本质上是一系列值)。

于 2009-11-21T17:04:22.513 回答