ljs*_*ljs 406 c# var type-inference
在与同事讨论了在C#3中使用'var'关键字后,我想知道人们对通过var的类型推断的适当用途有什么看法?
例如,我在可疑情况下懒得使用var,例如: -
foreach(var item in someList) { // ... } // Type of 'item' not clear.
var something = someObject.SomeProperty; // Type of 'something' not clear.
var something = someMethod(); // Type of 'something' not clear.
Run Code Online (Sandbox Code Playgroud)
var的更合理用途如下: -
var l = new List<string>(); // Obvious what l will be.
var s = new SomeClass(); // Obvious what s will be.
Run Code Online (Sandbox Code Playgroud)
有趣的是LINQ似乎有点灰色,例如: -
var results = from r in dataContext.SomeTable
select r; // Not *entirely clear* what results will be here.
Run Code Online (Sandbox Code Playgroud)
很明显,结果会是什么,它将是一个实现IEnumerable的类型,但是以声明一个新对象的var的方式并不完全明显.
对于LINQ对象来说更糟糕的是,例如:
var results = from item in someList
where item != 3
select item;
Run Code Online (Sandbox Code Playgroud)
这并不比等效的foreach(someList中的var项){// ...}等效更好.
这里有关于类型安全的真正担忧 - 例如,如果我们将该查询的结果放入一个接受IEnumerable <int>和IEnumerable <double>的重载方法,则调用者可能无意中传入了错误的类型.
var 确实保持强类型,但问题是这个类型在定义上不是立即显而易见是危险的,当重载意味着当你无意中将错误类型传递给方法时可能不会发出编译器错误时会放大某些东西.
Mat*_*ton 293
我仍然认为var在某些情况下可以使代码更具可读性.如果我有一个带有Orders属性的Customer类,并且我想将它分配给变量,我将这样做:
var orders = cust.Orders;
Run Code Online (Sandbox Code Playgroud)
我不在乎Customer.Orders是IEnumerable<Order>,ObservableCollection<Order>或者BindingList<Order>- 我想要的是将该列表保留在内存中以迭代它或者稍后获得它的计数.
将上述声明与以下内容对比:
ObservableCollection<Order> orders = cust.Orders;
Run Code Online (Sandbox Code Playgroud)
对我来说,类型名称只是噪音.如果我回去,并决定改变Customer.Orders类型走下赛场(假定从ObservableCollection<Order>到IList<Order>),那么我需要改变声明过-这是我不会做,如果我会在第一次使用VAR地点.
Kon*_*lph 167
我var广泛使用.有人批评这会降低代码的可读性,但没有论据支持这种说法.
不可否认,这可能意味着我们正在处理的类型尚不清楚.所以呢?这实际上是解耦设计的重点.在处理接口时,您显然对变量的类型不感兴趣.var借此更进一步,真实的,但我认为争论依然从一个可读性一点是相同的:程序员不应该真正感兴趣的变量,而是在什么一个变量的类型呢.这就是为什么微软也称类型推断为"鸭子打字".
那么,当我声明它使用时,变量会做什么var?很容易,它可以做任何IntelliSense告诉我的事情.关于忽略IDE的C#的任何推理都不符合现实.实际上,每个C#代码都在支持IntelliSense的IDE中编程.
如果我使用var声明的变量并且混淆了变量的作用,那么我的代码就会出现根本性的错误.var不是原因,它只会使症状可见.不要责怪信使.
现在,C#团队已经发布了编码指引,指出var应该只被用于捕获,创建一个匿名类型(因为在这里,我们有没有真正的替代一个LINQ语句的结果var).好吧,搞砸了.只要C#团队没有给我这个指南的合理论据,我就会忽略它,因为在我的专业和个人看来,它是纯粹的胡扯.(对不起;我没有指向相关指南的链接.)
实际上,有一些(表面上)很好的解释为什么你不应该使用,var但我仍然认为它们在很大程度上是错误的.以"searchabililty"为例:作者声称var难以搜索使用过的地方MyType.对.接口也是如此.实际上,为什么我想知道课程的使用位置?我可能对它实例化的地方更感兴趣,这仍然是可搜索的,因为必须调用它的构造函数(即使这是间接完成的,也必须在某处提到类型名称).
tva*_*son 118
VAR,在我看来,在C#是一个好事TM.所有类型的变量仍然是强类型的,但它从定义它的赋值的右侧获得它的类型.因为类型信息在右侧可用,所以在大多数情况下,还必须在左侧输入它,这是不必要的并且过于冗长.我认为这显着提高了可读性而不降低类型安全性.
从我的角度来看,从可读性角度来看,对变量和方法使用良好的命名约定比显式类型信息更重要.如果我需要类型信息,我总是可以将鼠标悬停在变量上(在VS中)并获取它.但是,通常,读者不需要显式类型信息.对于开发人员,在VS中,无论变量如何声明,您仍然可以获得Intellisense.说完所有这些之后,可能仍然存在明确声明类型有意义的情况 - 也许你有一个返回a的方法List<T>,但你想把它当作一个IEnumerable<T>在你的方法.要确保使用该接口,声明接口类型的变量可以使其显式化.或者,您可能希望声明一个没有初始值的变量 - 因为它会立即根据某些条件获取值.在这种情况下,您需要类型.如果类型信息有用或必要,请继续使用它.但我觉得通常没有必要,在大多数情况下,如果没有它,代码就更容易阅读.
Ada*_*son 91
这些都不是绝对正确的; var可以对可读性产生正面和负面影响.在我看来,var当以下任何一种情况属实时应该使用:
var foo = new TypeWithAReallyLongNameTheresNoSenseRepeating()),类型是显而易见的var没有性能影响,因为它是语法糖; 编译器推断出类型,并在编译成IL后定义它; 没有什么实际的动态了.
Dus*_*man 68
来自C#团队的高级软件设计工程师Eric Lippert:
为什么要var引入关键字?
有两个原因,一个存在于今天,一个将在3.0中出现.
第一个原因是,由于所有冗余,这段代码非常难看:
Dictionary<string, List<int>> mylists = new Dictionary<string, List<int>>();这是一个简单的例子 - 我写得更糟.每当你被迫两次输入完全相同的东西时,这就是我们可以删除的冗余.写得好多了
var mylists = new Dictionary<string,List<int>>();让编译器根据赋值找出类型.
其次,C#3.0引入了匿名类型.由于定义的匿名类型没有名称,因此如果其类型是匿名的,则需要能够从初始化表达式推断变量的类型.
强调我的.整篇文章,C#3.0仍然静态打字,老实说!,随后的系列非常好.
这var是为了什么.其他用途可能不会那么好用.与JScript,VBScript或动态类型的任何比较都是总上铺.注意再次,var是需要为了在.NET某些其他功能的工作.
Mat*_*ton 53
我认为var的使用应该与明智选择的变量名称相结合.
我在foreach语句中使用var没有问题,前提是它不是这样的:
foreach (var c in list) { ... }
Run Code Online (Sandbox Code Playgroud)
如果它更像这样:
foreach (var customer in list) { ... }
Run Code Online (Sandbox Code Playgroud)
...那么阅读代码的人将更有可能理解"列表"是什么.如果您可以控制列表变量本身的名称,那就更好了.
这同样适用于其他情况.这很没用:
var x = SaveFoo(foo);
Run Code Online (Sandbox Code Playgroud)
......但这是有道理的:
var saveSucceeded = SaveFoo(foo);
Run Code Online (Sandbox Code Playgroud)
我想每个都是他自己的.我发现自己这样做,这只是疯了:
var f = (float)3;
Run Code Online (Sandbox Code Playgroud)
我需要某种12步var程序.我的名字是Matt,我(ab)使用var.
Dex*_*ter 40
我们采用了"人而不是机器代码"的理念,假设您在维护模式上花费的时间比在新开发上多花费多倍.
对我来说,这排除了编译器"知道"变量的类型的论点 - 当然,你不能在第一次编写无效代码,因为编译器会停止编译代码,但是当下一个开发人员正在阅读代码时在6个月的时间内,他们需要能够正确或错误地推断出变量的作用,并快速确定问题的原因.
从而,
var something = SomeMethod();
Run Code Online (Sandbox Code Playgroud)
我们的编码标准是非法的,但我们的团队鼓励以下内容,因为它提高了可读性:
var list = new List<KeyValuePair<string, double>>();
FillList( list );
foreach( var item in list ) {
DoWork( item );
}
Run Code Online (Sandbox Code Playgroud)
Ion*_*rel 39
它不错,它更像是一种风格,往往是主观的.当你使用var时,它可以添加不一致性.
另一个值得关注的案例,在下面的调用中,您无法通过查看返回类型的代码来判断CallMe:
var variable = CallMe();
Run Code Online (Sandbox Code Playgroud)
这是我对var的主要抱怨.
当我在方法中声明匿名委托时,我使用var,不知何故var看起来比我使用的更干净Func.考虑以下代码:
var callback = new Func<IntPtr, bool>(delegate(IntPtr hWnd) {
...
});
Run Code Online (Sandbox Code Playgroud)
编辑:根据Julian的输入更新了最后一个代码示例
Kat*_*ory 36
Var根本不像变种.该变量仍然是强类型的,只是你没有按键来获得它.您可以将鼠标悬停在Visual Studio中以查看其类型.如果您正在阅读打印的代码,那么您可能需要考虑一下才能弄清楚类型是什么.但是只有一行声明它并且许多行使用它,因此给出正确的名称仍然是使代码更容易理解的最佳方式.
使用Intellisense懒惰?打字比整个名字少.或者有些东西工作少但不值得批评?我认为有,而var就是其中之一.
Mar*_*ell 27
您最需要的时间是匿名类型(需要100%); 但它也避免了重复的微不足道的情况,IMO使线条更清晰.对于简单的初始化,我不需要看两次类型.
例如:
Dictionary<string, List<SomeComplexType<int>>> data = new Dictionary<string, List<SomeComplexType<int>>>();
Run Code Online (Sandbox Code Playgroud)
(请不要编辑上面的hscroll - 它有点证明了这一点!!!)
VS:
var data = new Dictionary<string, List<SomeComplexType<int>>>();
Run Code Online (Sandbox Code Playgroud)
但是,有时这会产生误导,并可能导致错误.var如果原始变量和初始化类型不相同,请小心使用.例如:
static void DoSomething(IFoo foo) {Console.WriteLine("working happily") }
static void DoSomething(Foo foo) {Console.WriteLine("formatting hard disk...");}
// this working code...
IFoo oldCode = new Foo();
DoSomething(oldCode);
// ...is **very** different to this code
var newCode = new Foo();
DoSomething(newCode);
Run Code Online (Sandbox Code Playgroud)
Jon*_*jap 17
var很难的一个特殊情况:离线代码审查,尤其是在纸上完成的代码审查.
你不能依靠鼠标悬停.
Fre*_*nge 17
我看不出有什么大不了的......
var something = someMethod(); // Type of 'something' not clear <-- not to the compiler!
Run Code Online (Sandbox Code Playgroud)
你仍然对'某事'有完整的智能感知,对于任何模棱两可的情况,你有单位测试,对吧?( 你呢? )
它不是varchar,它不是暗淡的,它肯定不是动态或弱打字.它正在停止像这样的maddnes:
List<somethinglongtypename> v = new List<somethinglongtypename>();
Run Code Online (Sandbox Code Playgroud)
并将整个思维结构减少到:
var v = new List<somethinglongtypename>();
Run Code Online (Sandbox Code Playgroud)
很好,不太好:
v = List<somethinglongtypename>();
Run Code Online (Sandbox Code Playgroud)
但那就是Boo的用途.
Guf*_*ffa 17
如果有人使用var关键字,因为他们不想"弄清楚类型",那肯定是错误的原因.在var不创建一个动态类型的变量关键字,编译器仍然必须知道的类型.由于变量始终具有特定类型,因此如果可能,类型也应在代码中明显.
使用var关键字的充分理由是例如:
写出数据类型通常会使代码更容易理解.它显示了您正在使用的数据类型,因此您不必通过首先确定代码的作用来确定数据类型.
Col*_*ond 11
鉴于Intellisense现在有多强大,我不确定var是否比在类中具有成员变量或在可见屏幕区域中定义的方法中的局部变量更难读.
如果你有一行代码如
IDictionary<BigClassName, SomeOtherBigClassName> nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();
Run Code Online (Sandbox Code Playgroud)
阅读比以下更容易或更难:
var nameDictionary = new Dictionary<BigClassName, SomeOtherBigClassName>();
Run Code Online (Sandbox Code Playgroud)
Mur*_*rph 10
我认为VAR的关键是只在适当的时候使用它,即在Linq中做它有助于(也可能在其他情况下)的事情.
如果你有一个类型的东西你应该使用它 - 不这样做是简单的懒惰(而不是通常被鼓励的创造性懒惰 - 优秀的程序员非常努力懒惰,可以考虑首先是事物的来源).
全面禁止与首先滥用构造一样糟糕,但确实需要一个合理的编码标准.
要记住的另一件事是它不是一个VB类型var,因为它不能改变类型 - 它是一个强类型变量,只是推断出类型(这就是为什么会有人认为它不是不合理的在一个foreach中使用它,但出于可读性和可维护性的原因,我不同意).
我怀疑这个会运行并运行( - :
墨菲
Blo*_*ard 10
当然,这int很容易,但是当变量的类型是IEnumerable<MyStupidLongNamedGenericClass<int, string>>,var使事情变得更容易.
不幸的是,你和其他人都错了.虽然我同意你的看法,冗余并不是一件好事,但解决这个问题的更好方法就是做以下事情:
MyObject m = new();
或者如果您传递参数:
Person p = new("FirstName","LastName");
在创建新对象的位置,编译器从左侧推断出类型,而不是从右侧推断出类型.这比"var"还有其他优点,因为它也可以用在字段声明中(还有一些其他区域也可以用,但我不会在这里介绍它).
最后,它并不是为了减少冗余.不要误解我的意思,"var"对于匿名类型/投影来说在C#中非常重要,但是这里的使用只是为了解决(我已经说了这么长时间),因为你混淆了正在使用.必须经常输入两次,但是将其声明为零次则太少了.
Nicholas Paldino .NET/C#MVP于2008年6月20日08:00 AM
我想如果你主要担心的是必须输入更少 - 那么就没有任何争论会影响你使用它.
如果你只打算永远是谁看你的代码的人,那么谁在乎呢?否则,在这种情况下:
var people = Managers.People
Run Code Online (Sandbox Code Playgroud)
没关系,但在这种情况下:
var fc = Factory.Run();
Run Code Online (Sandbox Code Playgroud)
它会使我的大脑从代码的"英语"开始形成任何即时类型的推论.
否则,只需使用您的最佳判断并对可能需要为您的项目工作的其他人进行"礼貌"编程.
使用var而不是显式类型使得重构变得更容易(因此我必须与先前的海报相矛盾,这些海报意味着它没有任何区别,或者它纯粹是"语法糖").
您可以更改方法的返回类型,而无需更改调用此方法的每个文件.想像
...
List<MyClass> SomeMethod() { ... }
...
Run Code Online (Sandbox Code Playgroud)
用的像
...
IList<MyClass> list = obj.SomeMethod();
foreach (MyClass c in list)
System.Console.WriteLine(c.ToString());
...
Run Code Online (Sandbox Code Playgroud)
如果你想重构SomeMethod()一个IEnumerable<MySecondClass>,你就必须foreach在你使用该方法的每个地方改变变量声明(也在里面).
如果你写
...
var list = obj.SomeMethod();
foreach (var element in list)
System.Console.WriteLine(element.ToString());
...
Run Code Online (Sandbox Code Playgroud)
相反,你不必改变它.
@aku:一个例子是代码审查.另一个例子是重构场景.
基本上我不想用鼠标打猎.它可能不可用.
这是一个品味问题.当你习惯了动态类型语言时,所有关于变量类型的烦恼都会消失.也就是说,如果你开始喜欢它们(我不确定是否每个人都可以,但我确实如此).
C#var非常酷,因为它看起来像动态类型,但实际上是静态类型 - 编译器强制正确使用.
变量的类型并不那么重要(之前已经说过了).从上下文(它与其他变量和方法的交互)及其名称应该相对清楚 - 不要指望customerList包含int...
我还在等着看我的老板对这个问题的看法 - 我有一个"继续"使用3.5中的任何新结构,但我们将如何处理维护?
在你IEnumerable<int>和IEnumerable<double>它之间的比较你不需要担心 - 如果你传递错误的类型,你的代码无论如何都不会编译.
对于类型安全没有任何顾虑,因为var它不是动态的.它只是编译器魔术,你所做的任何类型的不安全的调用都会被捕获.
Var Linq绝对需要:
var anonEnumeration =
from post in AllPosts()
where post.Date > oldDate
let author = GetAuthor( post.AuthorId )
select new {
PostName = post.Name,
post.Date,
AuthorName = author.Name
};
Run Code Online (Sandbox Code Playgroud)
现在看看intellisense 中的anonEnumeration,它会出现类似的东西IEnumerable<'a>
foreach( var item in anonEnumeration )
{
//VS knows the type
item.PostName; //you'll get intellisense here
//you still have type safety
item.ItemId; //will throw a compiler exception
}
Run Code Online (Sandbox Code Playgroud)
C#编译器非常聪明 - 如果它们的属性匹配,单独生成的anon类型将具有相同的生成类型.
除此之外,只要你有智能感知,var在上下文清晰的任何地方使用是很有意义的.
//less typing, this is good
var myList = new List<UnreasonablyLongClassName>();
//also good - I can't be mistaken on type
var anotherList = GetAllOfSomeItem();
//but not here - probably best to leave single value types declared
var decimalNum = 123.456m;
Run Code Online (Sandbox Code Playgroud)
我想这取决于你的观点.我个人从来没有因为var"误用"而理解一段代码有任何困难,而且我的同事和我全都使用它.(我同意Intellisense在这方面是一个巨大的帮助.)我欢迎它作为一种消除重复性的方法.
毕竟,如果声明如此
var index = 5; // this is supposed to be bad
var firstEligibleObject = FetchSomething(); // oh no what type is it
// i am going to die if i don't know
Run Code Online (Sandbox Code Playgroud)
实际上是不可能处理的,没有人会使用动态类型语言.
只有在清楚地看到使用什么类型时我才使用var.
例如,在这种情况下我会使用var,因为您可以立即看到x将是"MyClass"类型:
var x = new MyClass();
Run Code Online (Sandbox Code Playgroud)
我不会在这种情况下使用var,因为你必须将鼠标拖过代码并查看工具提示以查看MyFunction返回的类型:
var x = MyClass.MyFunction();
Run Code Online (Sandbox Code Playgroud)
特别是,在右侧甚至不是方法的情况下,我从不使用var,而只是一个值:
var x = 5;
Run Code Online (Sandbox Code Playgroud)
(因为编译器无法知道我是否需要byte,short,int或者其他)
对我来说,反感var表明为什么.NET中的双语是重要的.对于那些也完成了VB .NET的C#程序员来说,其优势var直观明显.标准C#声明:
List<string> whatever = new List<string>();
Run Code Online (Sandbox Code Playgroud)
在VB .NET中,输入以下内容是等效的:
Dim whatever As List(Of String) = New List(Of String)
Run Code Online (Sandbox Code Playgroud)
但是,在VB .NET中没有人这样做.这将是愚蠢的,因为自.NET的第一个版本以来你已经能够做到这一点......
Dim whatever As New List(Of String)
Run Code Online (Sandbox Code Playgroud)
...创建变量并在一个相当紧凑的行中初始化它.啊,但如果你想要一个IList<string>,而不是一个List<string>怎么办?好吧,在VB .NET中,这意味着你必须这样做:
Dim whatever As IList(Of String) = New List(Of String)
Run Code Online (Sandbox Code Playgroud)
就像你必须在C#中做的那样,显然不能var用于:
IList<string> whatever = new List<string>();
Run Code Online (Sandbox Code Playgroud)
如果你需要类型不同的东西,它可以.但良好编程的基本原则之一是减少冗余,而这正是var所做的.
将它用于匿名类型 - 这就是它的用途.其他任何东西都用得太过分了.像很多在C上长大的人一样,我习惯于查看声明类型的左边.除非必须,否则我不会看右边.使用var任何旧的声明让我一直这样做,我个人觉得不舒服.
那些说"没关系,用你满意的东西"的人并没有看到全局.每个人都会在某个时刻接受其他人的代码,并且必须处理他们在编写代码时做出的任何决定.不得不处理完全不同的命名惯例,或者 - 经典的抱抱式支撑风格,而不是将整个' var或不是' 添加到组合中.最糟糕的情况是一个程序员不使用的地方var然后是一个喜欢它的维护者,并使用它扩展代码.所以现在你有一个邪恶的混乱.
标准是一件好事,正是因为它们意味着你更有可能获得随机代码并能够快速完成它.不同的东西越多,越难.转向'var everywhere'风格会产生很大的不同.
我不介意动态打字,我不介意打印输入 - 用于为他们设计的语言.我非常喜欢Python.但是C#被设计为一种静态明确类型的语言,它应该如何保留.打破匿名类型的规则已经够糟糕了; 让人们更进一步,进一步打破语言的习语,这是我不满意的事情.既然精灵已经不在瓶子里了,它就永远不会再回来了.C#将会变成阵营.不好.
很多时候在测试过程中,我发现自己有这样的代码:
var something = myObject.SomeProperty.SomeOtherThing.CallMethod();
Console.WriteLine(something);
Run Code Online (Sandbox Code Playgroud)
现在,有时,我想看看SomeOtherThing本身包含的内容,SomeOtherThing与CallMethod()返回的类型不同.因为我使用var,我只是改变了这个:
var something = myObject.SomeProperty.SomeOtherThing.CallMethod();
Run Code Online (Sandbox Code Playgroud)
对此:
var something = myObject.SomeProperty.SomeOtherThing;
Run Code Online (Sandbox Code Playgroud)
如果没有var,我还必须继续改变左侧的声明类型.我知道它很小,但非常方便.
小智 6
对于想要var节省时间的afficionados,键入的键击次数更少:
StringBuilder sb = new StringBuilder();
Run Code Online (Sandbox Code Playgroud)
比
var sb = new StringBuilder();
Run Code Online (Sandbox Code Playgroud)
如果你不相信我,请算上他们......
19对21
我会解释是否必须,但只是尝试一下......(取决于你的智能感知的当前状态,你可能需要为每一个输入更多)
对于你能想到的每种类型都是如此!
我的个人感觉是永远不应该使用var,除非类型未知,因为它会降低代码中的识别可读性.识别类型比整行更需要大脑.了解机器代码和位的老定时器确切地知道我在说什么.大脑并行处理,当你使用var时,你强制它序列化它的输入.为什么有人想让他们的大脑更努力?这就是计算机的用途.
从我昨天写的代码来看,它当然可以简化事情:
var content = new Queue<Pair<Regex, Func<string, bool>>>();
...
foreach (var entry in content) { ... }
Run Code Online (Sandbox Code Playgroud)
没有,这将是非常冗长的var.
附录:使用具有真实类型推断的语言花费一点时间(例如F#)将显示编译器在获得正确类型的表达方面有多好.它当然意味着我倾向于var尽可能多地使用,现在使用显式类型表明该变量不是初始化表达式的类型.
在大多数情况下,输入它只是更简单 - 想象一下
var sb = new StringBuilder();
Run Code Online (Sandbox Code Playgroud)
代替:
StringBuilder sb = new StringBuilder();
Run Code Online (Sandbox Code Playgroud)
有时它是必需的,例如:匿名类型,如.
var stuff = new { Name = "Me", Age = 20 };
Run Code Online (Sandbox Code Playgroud)
我个人喜欢使用它,尽管它使代码的可读性和可维护性降低.
我以前认为var关键字是一个伟大的发明,但我对它有一个限制
我开始意识到这一点然后给了我任何好处并从我的代码中删除了所有var关键字(除非他们是特别需要的),现在我认为它们使代码的可读性降低,特别是对其他人来说,阅读代码.
由于假设类型,它隐藏了意图并且至少在一个实例中导致某些代码中的运行时错误.