【问题标题】:implictly typed local variable 'var' to an explicitly typed local variable隐式类型的局部变量 'var' 到显式类型的局部变量
【发布时间】:2013-09-05 08:45:51
【问题描述】:

假设我有一个相当复杂的表达式,以这个表达式为例,我想用显式变量替换 var?

var collection = Enumerable.Range(0, 10)
   .Where(x => x % 2 != 0)
   .Reverse()
   .Select(x => new { 
                       original = x, 
                       sqrt = Math.Sqrt(x) 
                    });

我尝试了很多组合来替换 var,但它不会一直给我一个错误。哦,至于 VS 告诉我它并没有真正帮助的类型......

例如我试过替换

var collection

IEnumerable<KeyValuePair<int, double>> collection

【问题讨论】:

  • Dictionary&lt;int, double&gt; collection = Enumerable.Range(0, 10) .Where(x =&gt; x % 2 != 0) .Reverse() .ToDictionary(x =&gt; x, x =&gt; Math.Sqrt(x));

标签: c# var implicit


【解决方案1】:

因为您选择的是new 对象,所以结果是Anonymous Type,并且您不能用类型替换var。

【讨论】:

  • 到目前为止,我所阅读的所有内容都表明,只要您知道类型,您就应该只使用 var;那么这会是规则的例外吗?
  • @DraconianTimes 在某种程度上,是否使用var 是一个品味问题(我在当地人尽可能使用它)。然而,这里的实际类型在未编译的代码中还没有名称(“匿名类型”),因此不能完全命名
  • @DraconianTimes 我不知道你在哪里读到的;如果你不能知道类型(因为它是匿名类型,或者是涉及匿名类型),那么你就不能使用任何exceptvar。如果你确实知道类型:就用最清楚的。
  • @DraconianTimes 你在哪里读到的?嗯,你知道类型。它是 the 匿名类型,具有两个属性,第一个称为 original,类型为 int,第二个称为 sqrt,类型为 double。这种类型是匿名的,这意味着它没有名字。因此请使用var
【解决方案2】:

如果你真的很想放一些东西,你可以使用

IEnumerable<dynamic> collection = Enumerable.Range(0, 10).Where(x => x % 2 != 0)
      .Reverse()
      .Select(x => new { original = x, sqrt = Math.Sqrt(x) });

你不能做更多的事情,因为你在你的表达式中创建了一个匿名对象。

请阅读 Jeppe Stig Nielsen 制作的 cmets,详细解释为什么即使可以这样做,您也不应该这样做。

【讨论】:

  • 您可以稍后使用IEnumerable&lt;dynamic&gt; 访问这些属性。使用object 你不能做很多事情(例如没有进一步的预测)。但通常最好在这里创建一个具体类型并投影到该类而不是匿名类型
  • 是的,你是对的,这是使用对象的缺点 :) 我纠正了答案,但是是的,我同意创建一个新类会使事情更容易理解。
  • 虽然这是可能的,但它只有缺点。你失去了类型安全,例如 collection.First().asdf(); 编译。而且您会失去性能,因为绑定(解析重载等成员)将需要在运行时进行。但是,如果你需要returncollection,你可能会考虑这样的事情,因为方法返回类型不能是var。但是,在这种情况下,最好使用类型安全的命名类型,例如 KeyValuePair&lt;int, double&gt;Tuple&lt;int, double&gt;
  • 我从来没有说过这很好或应该这样做(在这两种情况下,我个人的回答都是不);他问他是否可以,我只是回答如何。我只能同意你所说的一切。
  • 另外,这只是因为IEnumerable&lt;out T&gt;T 中是协变的。假设您想要一个List&lt;&gt;。您将在Select(...) 之后附加.ToList()。现在你不能在那种情况下使用List&lt;dynamic&gt;!当涉及匿名类型时,请务必使用var。您确实知道强类型是什么,但您只是不想为该类型命名。
【解决方案3】:

你可能想要这样的东西

IEnumerable<KeyValuePair<int, double>> collection = 
        Enumerable.Range(0, 10)
                  .Where(x => x%2 != 0)
                  .Reverse()
                  .Select(x => new KeyValuePair<int, double> (x,Math.Sqrt(x)));

【讨论】:

    【解决方案4】:

    我认为最简洁的方法是将您的匿名类型转换为显式声明的类:

    public static void Main(string[] args)
    {
        IEnumerable<WithRoot> collection = Enumerable.Range(0, 10)
           .Where(x => x % 2 != 0)
           .Reverse()
           .Select(x => new WithRoot(x, Math.Sqrt(x)));    
    }
    
    private sealed class WithRoot
    {
        public WithRoot(int orig, double root)
        {
            this.Original = orig;
            this.SquareRoot = root;
        }
    
        public int Original { get; private set; }
    
        public double SquareRoot { get; private set; }
    }
    

    这使您可以在代码中命名类型,同时保持完整的类型安全(与dynamicobject 的解决方案相比)。但是,它会使您的代码更加冗长。坦率地说,我怀疑您是否需要它,并且我不鼓励您仅仅为了显式键入而这样做。 var 不坏/邪恶。

    功能差异:请注意,EqualsGetHashCode 在我的代码示例中没有被覆盖。当您使用匿名类型时,这也会自动发生。

    【讨论】:

    • 使用类还允许将结果存储在字段中或传递给方法 - 然后再次使用 IEnumerable&lt;KeyValuePair&lt;int, double&gt;&gt; 也可以这样做。
    猜你喜欢
    • 2010-10-13
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    相关资源
    最近更新 更多