有趣的“参考参考”功能,任何解决方法?

时间:2009-11-21 16:55:05

标签: c# reference extension-methods params

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

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

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

除了将值类型包装到引用类型中(通过创建另一个类),有没有办法在使用params修饰符时通过引用(ref)将变量传递给函数?

5 个答案:

答案 0 :(得分:21)

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

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

有意义吗?

答案 1 :(得分:2)

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

在Delphi中我可以做这样的事情:

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

//&lt; - “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行代码可以完成我在一行Delphi代码中所做的工作。我认为在某个地方有一个公式,代码中的错误的可能性随着代码行的数量而几何增加;因此,如果你有20行代码,你的代码错误的可能性是你的代码的10倍。

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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

void OnCheckBoxCheckedChanged(object sender, CheckedChangedEventArgs e)
{
    var cb = (CheckBox)sender;
    var item = (MyModel)cb.BindingContext;
    var id = item.ArtikelID;
}

代理可以递归声明。

在外部返回一个函数,然后再次调用。

您将被代码审查员杀死。


广告OW <:CWKSC/MyLib_Csharp

答案 4 :(得分:0)

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