2014-12-05 67 views
2

給定一個類和名稱空間,定義如下;對未定義名稱空間中定義類型的類型推斷

namespace Models 
{ 
    public class Foo 
    { 
    } 
} 

而下面......

namespace Factories 
{ 
    using Models; 

    class FooFactory 
    { 
     public Foo GetFoo() 
     { 
      return new Foo(); 
     } 
    } 
} 

最後...

namespace InferenceTest 
{ 
    using Factories; 

    class Program 
    { 
     static void Main() 
     { 
      Foo foo = new FooFactory().GetFoo(); 
     } 
    } 
} 

正如你所期望的,該代碼失敗,出現錯誤「的類型或編譯名稱空間名稱'Foo'無法找到(您是否缺少使用指令或程序集引用?)「

但是,如果我行更改爲這個...

var foo = new FooFactory().GetFoo(); 

然後編譯和運行得很好。

爲什麼會有這種差異?類型推斷是什麼使它能夠查看尚未導入的名稱空間中的類型。命名空間只是語法糖嗎?

+0

我不知道這足夠好發表權威的答案,但是我會說當你使用'var'你將它留給編譯器來確定類型,所以有一個合格的命名空間將是沒有幫助的,因爲它知道類型是什麼。當使用顯式類型時,可能指的是具有相同名稱(不同名稱空間)的不同類型,因此必須明確如何限定類型。 – Lukazoid 2014-12-05 13:43:40

+3

您不必有一個using指令來聲明該類型的變量,它只是允許您使用縮短的類型聲明。 'Models.Foo foo = new FooFactory()。GetFoo();'會編譯得很好。使用var它並不重要什麼使用指令,因爲你不是說「聲明這個特定類型的變量foo」你在說「聲明可變foo並從初始化中推斷出這個類型」。 – 2014-12-05 13:44:18

+0

噢好吧,所以「var」實際上只是被全限定類型名稱替換。「Models.Foo」? – 2014-12-05 13:46:50

回答

2

編譯var foo = new FooFactory().GetFoo();的原因很簡單。編譯器推斷foo是Models.Foo類型不僅是Foo。
Models.Foo foo2 = new FooFactory().GetFoo();相似。
請注意,Foo foo2 = new FooFactory().GetFoo();是不同的。

1

namespaces that have not been imported是你無效的原因;你不會導入命名空間,但可以像使用本地一樣使用它們。編譯過程中唯一導入的是引用程序集,即使它不是真正的導入,只是導入了一些元數據。 (如版本和GUID)

這意味着當您引用程序集(如System.dll)時,可以使用其中的所有類;向您展示它的意義時,我會給你這個反射例如:

internal class Program { 
    private static void Main() { 
     System.Type.GetType("System.Console") 
      .GetMethod("WriteLine",new[] {System.Type.GetType("System.String")}) 
      .Invoke(null,new object[]{"Hello World"}); 
    } 
} 

你沒有「進口」的任何命名空間,但仍然使用stringConsoleWriteLine和一些反射功能,而不需要編譯器知道它在編譯時間,因爲您有System.dll引用到您的項目。