VB.NET 'With' 声明 - 接受还是避免?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/283749/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
The VB.NET 'With' Statement - embrace or avoid?
提问by Tom
At work, I'm frequently working on projects where numerous properties of certain objects have to be set during their construction or early during their lifetime. For the sake of convenience and readability, I often use the With
statement to set these properties. I find that
在工作中,我经常参与一些项目,在这些项目中,某些对象的许多属性必须在它们的构建过程中或生命周期的早期进行设置。为了方便和可读性,我经常使用With
语句来设置这些属性。我发现
With Me.Elements
.PropertyA = True
.PropertyB = "Inactive"
' And so on for several more lines
End With
Looks much better than
看起来比
Me.Elements.PropertyA = True
Me.Elements.PropertyB = "Inactive"
' And so on for several more lines
for very long statements that simply set properties.
用于简单设置属性的非常长的语句。
I've noticed that there are some issues with using With
while debugging; however, I was wondering if there were any compelling reasons to avoid using With
in practice? I've always assumed the code generated via the compiler for the above two cases is basically the same which is why I've always chosen to write what I feel to be more readable.
我注意到With
在调试时使用存在一些问题;但是,我想知道是否有任何令人信服的理由避免With
在实践中使用?我一直假设通过编译器为上述两种情况生成的代码基本相同,这就是为什么我总是选择编写我觉得更具可读性的内容。
采纳答案by Stefan
If you have long variablenames and would end up with:
如果您有很长的变量名并且最终会得到:
UserHandler.GetUser.First.User.FirstName="Stefan"
UserHandler.GetUser.First.User.LastName="Karlsson"
UserHandler.GetUser.First.User.Age="39"
UserHandler.GetUser.First.User.Sex="Male"
UserHandler.GetUser.First.User.Occupation="Programmer"
UserHandler.GetUser.First.User.UserID="0"
....and so on
then I would use WITH to make it more readable:
然后我会使用 WITH 使其更具可读性:
With UserHandler.GetUser.First.User
.FirstName="Stefan"
.LastName="Karlsson"
.Age="39"
.Sex="Male"
.Occupation="Programmer"
.UserID="0"
end with
In the later example there are even performance benefit over the first example because in the first example Im fetching the user every time I access a user property and in the WITH-case I only fetch the user one time.
在后面的示例中,甚至比第一个示例有性能优势,因为在第一个示例中,我每次访问用户属性时都获取用户,而在 WITH 的情况下,我只获取用户一次。
I can get the performance gain without using with, like this:
我可以在不使用 with 的情况下获得性能提升,如下所示:
dim myuser as user =UserHandler.GetUser.First.User
myuser.FirstName="Stefan"
myuser.LastName="Karlsson"
myuser.Age="39"
myuser.Sex="Male"
myuser.Occupation="Programmer"
myuser.UserID="0"
But I would go for the WITH statement instead, it looks cleaner.
但我会选择 WITH 语句,它看起来更干净。
And I just took this as an example so dont complain over a class with many keywords, another example could be like: WITH RefundDialog.RefundDatagridView.SelectedRows(0)
我只是以此为例,所以不要抱怨一个有很多关键字的类,另一个例子可能是: WITH RefundDialog.RefundDatagridView.SelectedRows(0)
回答by John Rudy
In practice, there are no really compelling points against it. I'm not a fan, but that's a personal preference, there's no empirical data to suggest that the With
construct is bad.
在实践中,没有真正令人信服的观点反对它。我不是粉丝,但这是个人喜好,没有经验数据表明该With
结构是坏的。
In .NET, it compiles to exactly the same code as fully-qualifying the object name, so there is no performance penalty for this sugar. I ascertained this by compiling, then disassembling, the following VB .NET 2.0 class:
在 .NET 中,它编译为与完全限定对象名称完全相同的代码,因此这种糖不会降低性能。我通过编译,然后反汇编以下 VB .NET 2.0 类来确定这一点:
Imports System.Text
Public Class Class1
Public Sub Foo()
Dim sb As New StringBuilder
With sb
.Append("foo")
.Append("bar")
.Append("zap")
End With
Dim sb2 As New StringBuilder
sb2.Append("foo")
sb2.Append("bar")
sb2.Append("zap")
End Sub
End Class
The disassembly is as follows -- note that the calls to sb2
's Append
method look identical to the With
statement calls for sb
:
反汇编如下 - 请注意,对sb2
的Append
方法的调用看起来与对 的With
语句调用相同sb
:
.method public instance void Foo() cil managed
{
// Code size 91 (0x5b)
.maxstack 2
.locals init ([0] class [mscorlib]System.Text.StringBuilder sb,
[1] class [mscorlib]System.Text.StringBuilder sb2,
[2] class [mscorlib]System.Text.StringBuilder VB$t_ref$L0)
IL_0000: nop
IL_0001: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.2
IL_0009: ldloc.2
IL_000a: ldstr "foo"
IL_000f: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_0014: pop
IL_0015: ldloc.2
IL_0016: ldstr "bar"
IL_001b: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_0020: pop
IL_0021: ldloc.2
IL_0022: ldstr "zap"
IL_0027: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_002c: pop
IL_002d: ldnull
IL_002e: stloc.2
IL_002f: newobj instance void [mscorlib]System.Text.StringBuilder::.ctor()
IL_0034: stloc.1
IL_0035: ldloc.1
IL_0036: ldstr "foo"
IL_003b: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_0040: pop
IL_0041: ldloc.1
IL_0042: ldstr "bar"
IL_0047: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_004c: pop
IL_004d: ldloc.1
IL_004e: ldstr "zap"
IL_0053: callvirt instance class [mscorlib]System.Text.StringBuilder [mscorlib]System.Text.StringBuilder::Append(string)
IL_0058: pop
IL_0059: nop
IL_005a: ret
} // end of method Class1::Foo
So if you like it, and find it more readable, go for it; there's no compelling reason not to.
因此,如果您喜欢它,并发现它更具可读性,那就去吧;没有令人信服的理由不这样做。
(By the way, Tom, I'm interested in knowing what happened with the debugger -- I can't recall ever seeing any unusual behavior in the debugger based on a With
statement, so I'm curious to know what behavior you did see.)
(顺便说一句,汤姆,我很想知道调试器发生了什么——我不记得根据With
语句在调试器中看到过任何异常行为,所以我很想知道你确实看到了什么行为.)
回答by JohnRC
There is a difference between using With and making repeating references to an object, which is subtle but should be borne in mind, I think.
使用 With 和重复引用对象是有区别的,我认为这很微妙,但应该牢记在心。
When a WITH statement is used, it creates a new local variable referencing the object. Subsequent references using .xx are references to properties of that local reference. If during the execution of the WITH statement, the original variable reference is changed, the object referenced by the WITH does not change. Consider:
当使用 WITH 语句时,它会创建一个新的引用该对象的局部变量。使用 .xx 的后续引用是对该本地引用的属性的引用。如果在WITH语句执行过程中,原来的变量引用发生了变化,WITH引用的对象不会发生变化。考虑:
Dim AA As AAClass = GetNextAAObject()
With AA
AA = GetNextAAObject()
'// Setting property of original AA instance, not later instance
.SomeProperty = SomeValue
End With
So, the WITH statement is not simply syntactical sugar, it is genuinely a different construct. Whilst you would be unlikely to code something explicit like the above, in some situations this might occur inadvertently so you should be aware of the issue. The most likely situation is where you may be traversing a structure such as a network of objects whose interconnections my be implicitly changed by setting properties.
因此,WITH 语句不仅仅是语法糖,它确实是一个不同的构造。虽然您不太可能像上述那样编写明确的代码,但在某些情况下,这可能是无意中发生的,因此您应该意识到这个问题。最可能的情况是您可能正在遍历一个结构,例如对象网络,其互连可能会通过设置属性隐式更改。
回答by phillihp
It's all about readability. Like all syntactic sugar, it can be overused.
这都是关于可读性的。像所有的语法糖一样,它可以被过度使用。
Embrace it IFyou're setting several members of an object over a few lines
如果您在几行中设置对象的多个成员,请拥抱它
With myObject
.Property1 = arg1
.Property2 = arg2
...
Avoiddoing anything else with "With"
避免用“With”做任何其他事情
If you write a With block that spans 50-100 lines and involves lots of other variables it can make it REALLY difficult to remember what was declared at the top of the block. For obvious reasons, I won't provide an example of such messy code
如果你编写了一个跨越 50-100 行并涉及许多其他变量的 With 块,它可能会让你很难记住在块顶部声明的内容。出于显而易见的原因,我不会提供这种凌乱代码的示例
回答by Jon Skeet
Where it makes the code genuinely more readable, go for it. Where it makes it lessreadable, avoid it - in particular, I suggest you avoid nesting With statements.
如果它使代码真正更具可读性,那就去做吧。如果它降低可读性,请避免使用它 - 特别是,我建议您避免嵌套 With 语句。
C# 3.0 has this feature solely for object initialization:
C# 3.0 具有此功能,仅用于对象初始化:
var x = new Whatever { PropertyA=true, PropertyB="Inactive" };
This is not only pretty much required for LINQ, but it also makes sense in terms of where the syntax doesn't indicate a code smell. I usually find that when I'm performing many different operations on an object beyond its initial construction, those operations should be encapsulated as a single one on the object itself.
这不仅是 LINQ 所必需的,而且在语法不指示代码异味的地方也很有意义。我通常会发现,当我对一个对象执行超出其初始构造的许多不同操作时,这些操作应该封装为对象本身的单个操作。
One note about your example - do you really need the "Me" at all? Why not just write:
关于你的例子的一个说明 - 你真的需要“我”吗?为什么不写:
PropertyA = True
PropertyB = "Inactive"
? Surely "Me" is implied in that case...
? 在这种情况下,肯定隐含了“我”......
回答by ljorquera
I would be suspicious of code that uses a lot this keyword: if it is used to make easier to set lots of instance variables or properties I think this may indicate that your classes are too large ( Large Class smell). If you use it to replace long chains of calls like this:
我会怀疑使用大量 this 关键字的代码:如果它用于更轻松地设置大量实例变量或属性,我认为这可能表明您的类太大(大类气味)。如果您使用它来替换像这样的长调用链:
UserHandler.GetUser.First.User.FirstName="Stefan"
UserHandler.GetUser.First.User.LastName="Karlsson"
UserHandler.GetUser.First.User.Age="39"
UserHandler.GetUser.First.User.Sex="Male"
UserHandler.GetUser.First.User.Occupation="Programmer"
UserHandler.GetUser.First.User.UserID="0"
then you are probably violating Demeter Law
那么你可能违反了德墨忒尔定律
回答by bart
I don't use VB.NET (I used to use plain VB) but...
我不使用 VB.NET(我曾经使用纯 VB)但是...
Is the leading dot mandatory? If so, then I don't see a problem. In Javascript, the result of using with
is that a property of an object looks just the same as a plain variable, and thatis very dangerous, as you don't see if you're accessing a property or a variable, and thus, with
is something to avoid.
前导点是强制性的吗?如果是这样,那么我看不出有什么问题。在Javascript中,使用的结果with
是,一个物体的外观的属性完全一样作为一个普通的变量,这是非常危险的,因为你没有看到,如果你访问属性或变量,因此,with
是要避免的东西。
Not only is its use easier on the eyes, but for repeated access to properties of an object, it's likely to be faster, as the object is fetched through the method chain only once, and not once for every property.
它的使用不仅在眼睛上更容易,而且对于重复访问对象的属性,它可能更快,因为对象只通过方法链获取一次,而不是每个属性都获取一次。
I do agree with other replies that you ought to avoid nested use of with
, for the same reason as why to avoid with
altogether in Javascript: because you no longer see what object your property belongs to.
我确实同意其他答复,您应该避免嵌套使用with
,原因与with
在 Javascript 中完全避免的原因相同:因为您不再看到您的财产属于哪个对象。
回答by soemirno
The 'with' is basically the 'cascade' from Smalltalk. It is a pattern in Kent Beck's Smalltalk Best Practice Patterns book.
“with”基本上是来自 Smalltalk 的“级联”。这是 Kent Beck 的 Smalltalk Best Practice Patterns 书中的一个模式。
A summary of the pattern: use it when it makes sense to group the messages sent to the object. Don't use it if it just happens to be some messages sent to the same object.
模式的总结:当需要对发送到对象的消息进行分组时使用它。如果恰好是一些消息发送到同一个对象,请不要使用它。
回答by soemirno
AVOID the WITH Blockat all costs(even readability). Two reasons:
不惜一切代价避免使用 WITH 块(即使是可读性)。两个原因:
- the Microsoft Documentation about With...End Withsays that in some circumstances, it creates a copy of the data on the stack, so any changes that you make will be thrown away.
- If you use it for LINQ Queries, the lambda results DO NOT Chain and so each intermediate clause's result is thrown away.
- 关于 With...End With的Microsoft 文档说,在某些情况下,它会在堆栈上创建数据的副本,因此您所做的任何更改都将被丢弃。
- 如果将其用于 LINQ 查询,则 lambda 结果不会链接,因此每个中间子句的结果都会被丢弃。
To describe this, we have a (broken) example from a Textbook that my co-worker had to ask the author about (it is indeed incorrect, the Names have been changed to protect... whatever):
为了描述这一点,我们有一个来自教科书的(损坏的)示例,我的同事不得不向作者询问(确实不正确,名称已更改以保护......无论如何):
With dbcontext.Blahs
.OrderBy(Function(currentBlah) currentBlah.LastName)
.ThenBy(Function(currentBlah) currentBlah.FirstName)
.Load()
End With
随着 dbcontext.Blahs
.OrderBy(Function(currentBlah) currentBlah.LastName)
.ThenBy(Function(currentBlah) currentBlah.FirstName)
.Load()
End With
The OrderBy and ThenBy have No Effectat all. IF you reformat the code by ONLY dropping the With and End With, and adding line continuation characters at the end of the first three lines... it works (as shown 15 pages laterin the same textbook).
OrderBy 和 ThenBy 根本没有效果。如果您仅通过删除 With 和 End With 并在前三行的末尾添加行继续符来重新格式化代码......它可以工作(如同一教科书后面的 15 页所示)。
We don't need any more reason to search and destroyWITH Blocks. They only had meaning in an Interpretedframework.
我们不再需要任何理由来搜索和销毁WITH Blocks。它们只在解释性框架中有意义。
回答by George Birbilis
There's a gotcha when using it with structures, aka you can't set their fields, since you're working on a local copy (made at time of entry in with block) of the "with" expression and not working with a (copy of an) object reference in that case:
将它与结构一起使用时有一个问题,也就是您无法设置它们的字段,因为您正在处理“with”表达式的本地副本(在进入 with 块时制作)而不是使用 (copy在这种情况下的 a) 对象引用:
The data type of objectExpression can be any class or structure type or even a Visual Basic elementary type such as Integer. If objectExpression results in anything other than an object, you can only read the values of its members or invoke methods, and you get an error if you try to assign values to members of a structure used in a With...End With statement. This is the same error you would get if you invoked a method that returned a structure and immediately accessed and assigned a value to a member of the function's result, such as GetAPoint().x = 1. The problem in both cases is that the structure exists only on the call stack, and there is no way a modified structure member in these situations can write to a location such that any other code in the program can observe the change.
The objectExpression is evaluated once, upon entry into the block. You can't reassign the objectExpression from within the With block.
objectExpression 的数据类型可以是任何类或结构类型,甚至可以是 Visual Basic 基本类型,例如 Integer。如果 objectExpression 产生的结果不是对象,则只能读取其成员的值或调用方法,并且如果尝试将值分配给 With...End With 语句中使用的结构的成员,则会出现错误。如果调用返回结构并立即访问并为函数结果的成员赋值的方法(例如 GetAPoint().x = 1),则会出现相同的错误。这两种情况下的问题是结构仅存在于调用堆栈中,在这些情况下,修改后的结构成员无法写入某个位置,以便程序中的任何其他代码都可以观察到更改。
objectExpression 在进入块时被评估一次。您不能从 With 块中重新分配 objectExpression。
guess the compiler could have been a bit more clever if you pass to with statement a structure name instead of an expression that returns a structure, but seems it's not
猜测编译器可能会更聪明一些,如果你传递给 with 语句一个结构名称而不是一个返回结构的表达式,但似乎不是