C# 当接口和实现都存在时,Var关键字类型推断不明确

C# 当接口和实现都存在时,Var关键字类型推断不明确,c#,C#,举个例子: interface IEntity { string Name { get; set; } } class Product : IEntity { public string Name { get; set; } public int Count { get; set; } // added member } class Client { void Process() { var product = new Product();

举个例子:

interface IEntity {
    string Name { get; set; }
}

class Product : IEntity {
    public string Name { get; set; }
    public int Count { get; set; } // added member
}

class Client {
    void Process() {
        var product = new Product();
        int count = product.Count; // this is valid            

    }
}

在上面的例子中,产品的类型是什么?是商业还是产品?似乎该产品属于具体实现(product)类型。如果是这样的话,var不应该只在特殊情况下使用吗。但我看到像resharper这样的工具建议默认使用var。一个程序不应该连接到一个接口吗?

var product=new product()
属于
product
类型。如果没有在接口之外使用成员,则可以对该接口编程(
Product.Count
不在
IEntity
接口上)

添加:


此外,在VS2008中,您可以将鼠标悬停在声明中的
var
关键字上以查看隐含类型。此悬停/工具提示消息也适用于声明行后的变量名。(来自,第211页)

如果在本例中使用
var
,则其类型将为
产品
。我不喜欢在默认情况下使用
var
,因为它有时会使阅读代码有点混乱


我更喜欢在
LINQ
查询中使用
var
,但尽量不要在其他地方过度使用它(如您的示例)。对于使用带有intellisense的IDE的人来说,这很好,但是如果你用记事本(或记事本++等)阅读代码,你将很难在不进行少量研究的情况下确定代码的类型。

如果你有一个像

class Product : IFirst, ISecond, IThrid

编译器唯一能做的理性的事情就是它能做什么。我不限制使用
var
,我在任何地方都使用它。我认为它使代码更具可读性。在这种情况下,我完全同意ReSharper的观点。

如果您仍然在方法中实例化具体类,那么您实际上不是在“编程到接口”,因为对具体产品类的依赖关系仍然存在。为了正确编程到接口,您必须删除新的实例化,例如使用工厂或IoC。

如果您希望
产品
的类型为
智能
,请尝试以下操作:

var product = new Product() as IEntity;
也就是说,是的,您应该编程到一个接口,但是在您的例子中,您直接实例化了具体类型。如果已经创建了对具体类型的依赖项,只需使用具体类型即可。如果不是,则使用工厂或注入来获取接口的实例<代码>风险值将很好地处理这些问题。例如:

public class MyExtremelySimpleFactoryExampleClass
{
  public IEntity Instantiate()
  {
    return new Product();
  }
}

// elsewhere in your code...
var item = myFactory.Instantiate(); // item is of type IEntity

最后,不,我不认为
var
应该只在“特殊情况”下使用。我发现它非常有用,并且几乎总是使用它

推断的类型是实际类型,而不是它可能实现/继承的任何接口或基类

考虑这一点:

var answer = "42";
如果它将推断接口而不是类型,那么变量类型将类似于
IComparable
,而不是
string


var
关键字的使用依赖于它推断实际类型,或者将其用于匿名类型以外的任何其他类型都没有意义。只要类型是明显的,就可以使用它使代码更可读,但是如果类型不是完全明显的,就应该避免使用它。(我上面的示例位于灰色区域,因为它实际上不包含
字符串
类型名称。)

这也是我的观点。事实上,在我的例子中,这是编程到接口的唯一方法。所以,是的,正如我所说,我不会在那种情况下使用它。我主要用于LINQ查询。重点是,变量“product”将始终默认为“product”类型(而不是IEntity),无论实现的类(product)是否有任何额外的成员,当使用var.时,您可以创建一个
ipproduct
界面,其中包括
Product
添加的成员。as用于强制转换,没有例外。它应该是var product=(IEntity)new product();