C#中与Visual Basic关键字'With' ... 'End With'的等价语句是什么?

10
在Visual Basic中,如果您要更改单个对象的多个属性,则可以使用With/End With语句:
Dim myObject as Object

// ' Rather than writing:
myObject.property1 = something
myObject.property2 = something2

// ' You can write:

with myObject
   .property1 = something
   .property2 = something2
   ...
End With

我知道在创建新对象时,C#可以做到这一点:
Object myObject = new Object { property1 = something, property2 = something2, ...};

如果myObject已经被创建了(就像Visual Basic所做的那样),那么我该如何做到这一点呢?


有些人说这是不好的,但我想指出微软的 VB.NET 编码规范表示,在对一个对象进行一系列调用时应该使用 With 关键字。- http://msdn.microsoft.com/en-us/library/h63fsef3.aspx - Dan Atkinson
可能是在C#中的With块等效物?的重复问题。 - StayOnTarget
7个回答

12

在C#中你无法这样做。

这个特性是VB特有的,而在C#中你能接近这个功能的方式就是使用对象初始化器(object initializer),如你所描述的那样。


6
这个怎么样?
static class Extension
{
    public static void With<T>(this T obj, Action<T> a)
    {
        a(obj);
    }    
}

class Program
{
    class Obj
    {
        public int Prop1 { get; set; }
        public int Prop2 { get; set; }
        public int Prop3 { get; set; }
        public int Prop4 { get; set; }
    }

    static void Main(string[] args)
    {
        var detailedName = new Obj();
        detailedName.With(o => {
            o.Prop1 = 1;
            o.Prop2 = 2;
            o.Prop3 = 3;
            o.Prop4 = 4;
        });
    }
}

把它变成扩展方法吧!然后你就可以像这样使用 detailedName.With(o => { o.Prop1 = 4 }) - Alxandr
2
顺便说一句,对于创意给个赞+1 :-) - Alxandr
注意:如果您使用Cadenza,它充满了很好的.NET扩展,您将获得一个具有完全相同实现的方法:http://www.gitorious.org/cadenza/cadenza/blobs/master/src/Cadenza/Cadenza/ObjectCoda.cs#line173 - John Feminella

3

如果你想避免大量输入,可以给你的对象起一个更短的名字:

var x = myObject;
x.property1 = something;
x.property2 = something2;

是的,为了更进一步,你甚至可以这样做 using(var x = myObject) {/*newline*/x.property1=something;} - Alxandr
3
很糟糕的想法,这将在块结束时调用“Dispose”(并且对于没有实现“IDisposable”的类型甚至无法编译)。 - Ben Voigt
哦,好观点。我的错。我只是认为它处理了“x”变量,但是由于它是引用,可能会导致灾难性的后果 :-P - Alxandr
如果你想让变量在使用完后超出作用域,你可以将代码放在花括号中以创建一个新的作用域。 - Mark Byers
1
避免大量的打字,真的吗?有了我们强大的智能感知功能?在我看来,这一切都是关于可读性。 - Jowen

3
为什么C#没有VB.NET的“with”运算符? 许多人,包括C#语言设计师,认为“with”经常会影响可读性,更像是一种诅咒而不是祝福。使用有意义的本地变量声明并使用该变量在单个对象上执行多个操作比具有某种隐含上下文的块更清晰。 由@Jon Skeet提供。

9
有些人认为,VB的“with”语句是一个有用的特性,提供了一些语义,这些语义不能通过其他方式方便地实现。 - supercat
2
有趣的是,他们称语法为诅咒,然后几乎在对象初始化语法中复制了它... - Darryl
这是 C# 中确实缺少的一件事。使用 With 语句在设置现有对象的多个属性时可以使代码更加简洁清晰。如果它真的那么糟糕,为什么在创建新对象时还要引入它呢? - csmith

2

@Mark Byers的回答很好,但变量x将在属性设置后继续存在。而且你不能再次使用名字为x的变量(在同一块中)。

尝试这个(在此示例中对象必须是引用类型):

void Main()
{
    var myObject1 = new Foo();
    var myObject2 = new Hoo();

    //elided...

    {
        var _ = myObject1;
        _.MyPropertyA = 2;
        _.MyPropertyB = "3";
    }

    {
        var _ = myObject2;
        _.MyPropertyX = 5;
        _.MyPropertyY = "asd";
    }
}

1

为了向后兼容,VB.NET包含了一些VB6的设计缺陷。虽然Javascript也有同样的设计缺陷(实际上更糟糕,因为它的with导致更多的歧义结构),但大多数其他C语法的编程语言却没有这个问题,因此在C#中添加它并没有向后兼容的好处。


实际上,在JavaScript中使用with有一个明显的优势。它允许您为函数引入新的作用域! - ChaosPandion
2
在VB中,当与结构一起使用时,“With”语句提供了在C中不方便使用的语义。鉴于VB的“With”使用前导句点以避免歧义,我不确定为什么您认为它是设计缺陷? - supercat

0
如果“with”表达式是一个类类型,那么“With”语句相当于创建一个新的临时变量,该变量的类型为该类型,并初始化为“With”表达式,并在每个前导“.”之前加上该变量。然而,如果它是一个结构类型,事情就更复杂了。考虑以下代码(显然不是人们通常编写代码的方式,但是为了说明问题而编写):
  With MyPoints(N) ' Point数组
    N=SomeNewValue
    .X = MyPoints(N).X
    .Y = MyPoints(N).Y
  End With

"With" 语句有效地锁定了对 MyPoints(N) 的引用。即使 MyPoints 更改为其他数组或 N 更改,锁定的引用仍将指向执行 With 语句时与相同数组的相同元素。如果声明一个类型为 Point 的局部变量 P 并获取 MyPoints(N),然后写入 P.X 和 P.Y,则写入只会命中本地副本 P,而不会更新数组。要在 C# 中实现类似的语义,必须使用本地变量来保持 MyPoints 和 N,或者将 With 语句的内容放在具有 Point 类型 ref 参数的匿名函数内。为避免在运行时创建闭包,匿名函数还应该通过引用(可能是按引用)接受外部范围中它所需的任何局部变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接