“var”的使用输入变量声明

发布于 2024-09-18 09:46:39 字数 198 浏览 14 评论 0原文

我们的内部审计建议我们使用显式变量类型声明,而不是使用关键字 var。他们认为使用 var“在某些情况下可能会导致意外结果”。

一旦代码编译为 MSIL,我不知道显式类型声明和使用 var 之间有什么区别。

审计师是一位受人尊敬的专业人士,所以我不能简单地拒绝这样的建议。

Our internal audit suggests us to use explicit variable type declaration instead of using the keyword var. They argue that using of var "may lead to unexpected results in some cases".

I am not aware of any difference between explicit type declaration and using of var once the code is compiled to MSIL.

The auditor is a respected professional so I cannot simply refuse such a suggestion.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

套路撩心 2024-09-25 09:46:40

使用 var 可能会隐藏逻辑编程错误,否则您会收到来自编译器或 IDE 的警告。请参阅此示例:

float distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);

此处,计算中的所有类型均为 int,并且您会收到有关可能丢失分数的警告,因为您在 float 变量中获取结果。

使用 var:

var distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);

这里您不会收到警告,因为 distX 的类型被编译为 int。如果您打算使用浮点值,那么这是一个对您隐藏的逻辑错误,并且很难在执行中发现,除非它在以后的计算中触发 除以零 异常(如果此初始值的结果)计算结果为<1。

Use of var might hide logical programming errors, that otherwise you would have got warning from the compiler or the IDE. See this example:

float distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);

Here, all the types in the calculation are int, and you get a warning about possible loss of fraction because you pick up the result in a float variable.

Using var:

var distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);

Here you get no warning because the type of distX is compiled as int. If you intended to use float values, this is a logical error that is hidden to you, and hard to spot in executing unless it triggers a divide by zero exception in a later calculation if the result of this initial calculation is <1.

假面具 2024-09-25 09:46:39

这个怎么样...

double GetTheNumber()
{
    // get the important number from somewhere
}

然后在其他地方...然后

var theNumber = GetTheNumber();
DoSomethingImportant(theNumber / 5);

,在未来的某个时刻,有人注意到 GetTheNumber 只返回整数,因此将其重构为返回 int 而不是double

砰!没有编译器错误,您开始看到意想不到的结果,因为以前的浮点运算现在已经变成了整数运算,而没有人注意到。

话虽如此,这种事情应该被你的单元测试等捕获,但这仍然是一个潜在的陷阱。

How about this...

double GetTheNumber()
{
    // get the important number from somewhere
}

And then elsewhere...

var theNumber = GetTheNumber();
DoSomethingImportant(theNumber / 5);

And then, at some point in the future, somebody notices that GetTheNumber only ever returns whole numbers so refactors it to return int rather than double.

Bang! No compiler errors and you start seeing unexpected results, because what was previously floating-point arithmetic has now become integer arithmetic without anybody noticing.

Having said that, this sort of thing should be caught by your unit tests etc, but it's still a potential gotcha.

话少情深 2024-09-25 09:46:39

我倾向于遵循这个方案:

var myObject = new MyObject(); // OK as the type is clear

var myObject = otherObject.SomeMethod(); // Bad as the return type is not clear

如果 SomeMethod 的返回类型发生变化,那么这段代码仍然可以编译。在最好的情况下,您会进一步遇到编译错误,但在最坏的情况下(取决于 myObject 的使用方式),您可能不会。在这种情况下,您可能会遇到很难追踪的运行时错误。

I tend to follow this scheme:

var myObject = new MyObject(); // OK as the type is clear

var myObject = otherObject.SomeMethod(); // Bad as the return type is not clear

If the return type of SomeMethod ever changes then this code will still compile. In the best case you get compile errors further along, but in the worst case (depending on how myObject is used) you might not. What you will probably get in that case is run-time errors which could be very hard to track down.

情场扛把子 2024-09-25 09:46:39

有些情况确实可能会带来意想不到的结果。我自己是 var 粉丝,但这可能会出错:

var myDouble = 2;
var myHalf = 1 / myDouble;

显然这是一个错误,而不是“意外结果”。但这一个陷阱......

Some cases could really lead to unexpected results. I'm a var fan myself, but this could go wrong:

var myDouble = 2;
var myHalf = 1 / myDouble;

Obviously this is a mistake and not an "unexpected result". But it is a gotcha...

谁把谁当真 2024-09-25 09:46:39

var 不是动态类型,它只是语法糖。唯一的例外是匿名类型。 来自 Microsoft 文档

<块引用>

在许多情况下,var 的使用是可选的,只是为了语法上的方便。但是,当使用匿名类型初始化变量时,如果稍后需要访问对象的属性,则必须将该变量声明为 var。

一旦编译为 IL,就没有区别除非您已将类型显式定义为与隐含类型不同的类型(尽管我无法想象为什么会这样做)。编译器不会让您在任何时候更改使用 var 声明的变量的类型。

来自 Microsoft 文档(再次)

隐式类型局部变量是强类型的,就像您自己声明类型一样,但编译器确定类型

。在某些情况下,var 可能会妨碍可读性。更多 Microsoft 文档 指出:

使用 var 至少有可能使其他开发人员更难以理解您的代码。因此,C# 文档通常仅在需要时才使用 var。

var is not a dynamic type, it is simply syntactic sugar. The only exception to this is with Anonymous types. From the Microsoft Docs

In many cases the use of var is optional and is just a syntactic convenience. However, when a variable is initialized with an anonymous type you must declare the variable as var if you need to access the properties of the object at a later point.

There is no difference once compiled to IL unless you have explicitly defined the type as different to the one which would be implied (although I can't think of why you would). The compiler will not let you change the type of a variable declared with var at any point.

From the Microsoft documentation (again)

An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type

In some cases var can impeed readability. More Microsoft docs state:

The use of var does have at least the potential to make your code more difficult to understand for other developers. For that reason, the C# documentation generally uses var only when it is required.

岁月如刀 2024-09-25 09:46:39

在非泛型世界中,每当发生隐式转换(例如在 foreach 循环内)时,使用 var 而不是类型时,您可能会得到不同的行为。

在下面的示例中,发生了从 objectXmlNode 的隐式转换(非泛型 IEnumerator 接口仅返回 object代码>)。如果您只是将循环变量的显式声明替换为 var 关键字,则不再发生这种隐式转换:

using System;
using System.Xml;

class Program
{
    static void Foo(object o)
    {
        Console.WriteLine("object overload");
    }

    static void Foo(XmlNode node)
    {
        Console.WriteLine("XmlNode overload");
    }

    static void Main(string[] args)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml("<root><child/></root>");

        foreach (XmlNode node in doc.DocumentElement.ChildNodes)
        {
            Foo(node);
        }

        foreach (var node in doc.DocumentElement.ChildNodes)
        {
            // oops! node is now of type object!
            Foo(node);
        }
    }
}

结果是,该代码实际上会根据您是否使用 var 产生不同的输出 或显式类型。使用 var 将执行 Foo(object) 重载,否则将执行 Foo(XmlNode) 重载。因此,上述程序的输出为:

XmlNode overload
object overload

请注意,此行为完全符合 C# 语言规范。唯一的问题是 var 推断出的类型 (object) 与您预期的不同,并且从代码中看,这种推断并不明显。

为了保持简短,我没有添加 IL。但如果您愿意,可以使用 ildasm 查看编译器实际上为两个 foreach 循环生成了不同的 IL 指令。

In the non-generic world you might get different behavior when using var instead of the type whenever an implicit conversion would occur, e.g. within a foreach loop.

In the example below, an implicit conversion from object to XmlNode takes place (the non-generic IEnumerator interface only returns object). If you simply replace the explicit declaration of the loop variable with the var keyword, this implicit conversion no longer takes place:

using System;
using System.Xml;

class Program
{
    static void Foo(object o)
    {
        Console.WriteLine("object overload");
    }

    static void Foo(XmlNode node)
    {
        Console.WriteLine("XmlNode overload");
    }

    static void Main(string[] args)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml("<root><child/></root>");

        foreach (XmlNode node in doc.DocumentElement.ChildNodes)
        {
            Foo(node);
        }

        foreach (var node in doc.DocumentElement.ChildNodes)
        {
            // oops! node is now of type object!
            Foo(node);
        }
    }
}

The result is that this code actually produces different outputs depending on whether you used var or an explicit type. With var the Foo(object) overload will be executed, otherwise the Foo(XmlNode) overload will be. The output of the above program therefore is:

XmlNode overload
object overload

Note that this behavior is perfectly according to the C# language specification. The only problem is that var infers a different type (object) than you would expect and that this inference is not obvious from looking at the code.

I did not add the IL to keep it short. But if you want you can have a look with ildasm to see that the compiler actually generates different IL instructions for the two foreach loops.

帅的被狗咬 2024-09-25 09:46:39

永远不应该使用 var 的说法很奇怪,因为它“在某些情况下可能会导致意外结果”,因为 C# 语言中存在比使用 var 复杂得多的微妙之处

其中之一是匿名方法的实现细节,这可能会导致 R# 警告“访问修改的闭包”以及您在查看代码时所期望的行为。与可以用几句话解释的 var 不同,此行为需要三篇很长的博客文章(其中包括反汇编程序的输出)才能完全解释:

这是否意味着您也不应该使用匿名方法(即委托、lambda)以及依赖它们的库(例如 Linq 或 ParallelFX),仅仅因为在某些奇怪的情况下行为可能不是您所期望的?

当然不是。

这意味着您需要了解您所使用的语言,了解其局限性和边缘情况,并测试事情是否按您的预期工作。由于语言功能“在某些情况下可能会导致意外结果”而排除它们,这意味着您只剩下很少的语言功能可供使用。

如果他们真的想争论这个问题,请让他们证明你的许多错误可以直接归因于 var 的使用,并且显式类型声明会阻止它们。我怀疑你很快就会收到他们的回复。

It's an odd claim that using var should never be used because it "may lead to unexpected results in some cases", because there are subtleties in the C# language far more complex than the use of var.

One of these is the implementation details of anonymous methods which can lead to the R# warning "Access to modified closure" and behaviour that is very much not what you might expect from looking at the code. Unlike var which can be explained in a couple of sentences, this behaviour takes three long blog posts which include the output of a disassembler to explain fully:

Does this mean that you also shouldn't use anonymous methods (i.e. delegates, lambdas) and the libraries that rely on them such as Linq or ParallelFX just because in certain odd circumstances the behaviour might not be what you expect?

Of course not.

It means that you need to understand the language you're writing in, know its limitations and edge cases, and test that things work as you expect them to. Excluding language features on the basis that they "may lead to unexpected results in some cases" would mean that you were left with very few language features to use.

If they really want to argue the toss, ask them to demonstrate that a number of your bugs can be directly attributed to use of var and that explicit type declaration would have prevented them. I doubt you'll hear back from them soon.

心房敞 2024-09-25 09:46:39

他们认为使用 var“可能会导致
在某些情况下会出现意想不到的结果“在某些情况下会出现意想不到的结果”。

如果意外的是,“我不知道如何阅读代码并弄清楚它在做什么”,那么是的,它可能会导致意外的结果。编译器必须根据围绕变量编写的代码知道该变量的类型。

var 关键字是编译时功能。编译器将为声明放入适当的类型。这就是为什么你不能做这样的事情:

var my_variable = null
or
var my_variable;

var 关键字很棒,因为你必须在代码本身中定义更少的信息。编译器会弄清楚它应该为你做什么。这几乎就像在使用接口时总是对接口进行编程一样(其中接口方法和属性由您在 var 定义的变量的声明空间中使用的内容定义)。如果变量的类型需要更改(当然在合理范围内),您无需担心更改变量声明,编译器会为您处理此问题。这听起来可能是一件微不足道的事情,但是如果您必须更改函数中的返回值,并且该函数在整个程序中都使用,会发生什么。如果您没有使用 var,那么您必须查找并替换调用该变量的每个位置。使用 var 关键字,您无需担心这一点。

They argue that using of var "may lead
to unexpected results in some cases".to unexpected results in some cases".

If unexpected is, "I don't know how to read the code and figure out what it is doing," then yes, it may lead to unexpected results. The compiler has to know what type to make the variable based on the code written around the variable.

The var keyword is a compile time feature. The compiler will put in the appropriate type for the declaration. This is why you can't do things like:

var my_variable = null
or
var my_variable;

The var keyword is great because, you have to define less information in the code itself. The compiler figures out what it is supposed to do for you. It's almost like always programming to an interface when you use it (where the interface methods and properties are defined by what you use within the declaration space of the variable defined by var). If the type of a variable needs to change(within reason of course), you don't need to worry about changing the variable declaration, the compiler handles this for you. This may sound like a trivial matter, but what happens if you have to change the return value in a function, and that function is used all throughout the program. If you didn't use var, then you have to find and replace every place that variable is called. With the var keyword, you don't need to worry about that.

指尖微凉心微凉 2024-09-25 09:46:39

当审计师必须制定指导方针时,最好是在“傻瓜安全”方面犯错,即将良好做法列入白名单/将不良做法列入黑名单,而不是告诉人们只要保持理智根据对当前情况的评估做正确的事情

如果您只是说“不要在代码中的任何地方使用 var”,您就可以消除编码指南中的许多歧义。这应该使代码看起来&感觉更加标准化,而不必解决何时做这个、何时做那个的问题。

我个人很喜欢 var。我将它用于所有局部变量。一直以来。如果结果类型不清楚,那么这不是 var 的问题,而是用于初始化变量的(命名)方法的问题......

When coming up with guidelines, as an auditor has to do, it is probably better to err on the side of fool safe, that is white listing good practices / black listing bad practices as opposed to telling people to simply be sensible and do the right thing based on an assessment of the situation at hand.

If you just say "don't use var anywhere in code", you get rid of a lot of ambiguity in the coding guidelines. This should make code look & feel more standardized without having to solve the question of when to do this and when to do that.

I personally love var. I use it for all local variables. All the time. If the resulting type is not clear, then this is not an issue with var, but an issue with the (naming of) methods used to initialize a variable...

你的背包 2024-09-25 09:46:39

在使用 var 关键字时,我遵循一个简单的原则。如果您事先知道类型,请不要使用 var。
在大多数情况下,我将 var 与 linq 一起使用,因为我可能想返回匿名类型。

I follow a simple principle when it comes to using the var keyword. If you know the type beforehand, don't use var.
In most cases, I use var with linq as I might want to return an anonymous type.

青柠芒果 2024-09-25 09:46:39

当你有明显的声明

ArrayList<Entity> en = new ArrayList<Enity>()

使可读性变得复杂

var en = new ArrayList<Entity>()

时,最好使用 var懒惰、清晰的代码,我喜欢它

var best using when you have obviously declaration

ArrayList<Entity> en = new ArrayList<Enity>()

complicates readability

var en = new ArrayList<Entity>()

Lazy, clear code, i like it

美人骨 2024-09-25 09:46:39

我仅在清楚变量的类型或根本不需要知道类型的情况下使用 var (例如 GetPerson() 应返回 Person,<代码>Person_Class等)。

我不使用 var 来表示原始类型、枚举和字符串。我也不将它用于值类型,因为值类型将通过赋值进行复制,因此应该显式声明变量的类型。

关于您的审计员意见,我想说的是,像我们每天所做的那样添加更多行代码也会“在某些情况下导致意外结果”。这个论点的有效性已经我们创建的这些错误已经证明了这一点,因此我建议永远冻结代码库以防止这种情况发生。

I use var only where it is clear what type the variable is, or where it is no need to know the type at all (e.g. GetPerson() should return Person, Person_Class, etc.).

I do not use var for primitive types, enum, and string. I also do not use it for value type, because value type will be copied by assignment so the type of variable should be declared explicitly.

About your auditor comments, I would say that adding more lines of code as we have been doing everyday also "lead to unexpected results in some cases". This argument validity has already proven by those bugs we created, therefore I would suggest freezing the code base forever to prevent that.

烦人精 2024-09-25 09:46:39

如果您知道类型是什么,则使用 var 是惰性代码。它只是更容易、更清晰地阅读。当查看大量代码时,更简单、更干净总是更好

using var is lazy code if you know what the type is going to be. Its just easier and cleaner to read. When looking at lots and lots of code, easier and cleaner is always better

何处潇湘 2024-09-25 09:46:39

使用 var 声明的变量和显式指定的变量声明的 IL 输出绝对没有区别(您可以使用反射器证明这一点)。我通常只将 var 用于长嵌套泛型类型、foreach 循环和匿名类型,因为我喜欢显式指定所有内容。其他人可能有不同的偏好。

There is absolutely no difference in the IL output for a variable declaration using var and one explicitly specified (you can prove this using reflector). I generally only use var for long nested generic types, foreach loops and anonymous types, as I like to have everything explicitly specified. Others may have different preferences.

隱形的亼 2024-09-25 09:46:39

var 只是使用显式类型声明的简写符号。

只能在某些情况下使用 var;使用 var 时,必须在声明时初始化变量。
您不能事后将其他类型的变量分配给该变量。

在我看来,许多人倾向于将 'var' 关键字与 VB6 中的 'Variant' 数据类型混淆。

var is just a shorthand notation of using the explicit type declaration.

You can only use var in certain circumstances; You'll have to initialize the variable at declaration time when using var.
You cannot assign a variable that is of another type afterwards to the variable.

It seems to me that many people tend to confuse the 'var' keyword with the 'Variant' datatype in VB6 .

夏尔 2024-09-25 09:46:39

我认为使用显式变量声明的“唯一”好处是,通过精心选择的类型名,您可以更清楚地说明代码段的意图(在我看来,这比其他任何事情都更重要)。 var 关键字的好处确实如 Pieter 所说。

The "only" benefit that i see towards using explicit variable declaration, is with well choosen typenames you state the intent of your piece of code much clearer (which is more important than anything else imo). The var keyword's benefit really is what Pieter said.

淡莣 2024-09-25 09:46:39

我还认为,如果你声明双打时末尾没有 D,你会遇到麻烦。当您编译发行版本时,您的编译器可能会去掉双精度并将它们设置为浮点数以节省空间,因为它不会考虑您的精度。

I also think that you will run into trouble if you declare your doubles without the D on the end. when you compile the release version, your compiler will likely strip off the double and make them a float to save space since it will not consider your precision.

你不是我要的菜∠ 2024-09-25 09:46:39

var 将编译为与可以指定的静态类型相同的内容。它只是消除了在代码中明确使用该类型的需要。它不是动态类型,并且不会/不能在运行时更改。我发现在 foreach 循环中使用它非常有用。

foreach(var item in items)
{
item.name = ______;
}

当使用枚举时,有时特定类型是未知的,查找起来很耗时。使用 var 而不是静态类型将产生相同的结果。
我还发现 var 的使用使重构变得更加容易。当使用不同类型的枚举时,不需要更新 foreach。

var will compile to the same thing as the Static Type that could be specified. It just removes the need to be explicit with that Type in your code. It is not a dynamic type and does not/can not change at runtime. I find it very useful to use in foreach loops.

foreach(var item in items)
{
item.name = ______;
}

When working with Enumerations some times a specific type is unknown of time consuming to lookup. The use of var instead of the Static Type will yeald the same result.
I have also found that the use of var lends it self to easier refactoring. When a Enumeration of a different type is used the foreach will not need to be updated.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文