Ahogy januárban már írtam róla, az új 4.5-ös .NET Framework verziószáma (nagyjából) pontosan meg fog egyezni a 4.0 verziószámával, azaz in-place upgrade történik. (Hogy ez mennyire jó ötlet, arról még mindig lehet szavazni a januári cikk végén.) Akkor azt fejtegettem, hogy ez milyen problémákat fog felvetni, amikor a 4.0-ra tesztelt alkalmazásaink észrevétlenül 4.5-ön kezdenek el majd futni.
Na de most nézzük a fordított irányt. Íme az alábbi kiváló kódom, amit Visual Studio 11 alatt készítettem, .NET 4.5-re fordítva:
static void Main(string[] args) { Console.WriteLine("Elindult."); Console.WriteLine("Vége."); Console.ReadLine(); }
Kiválóan fut Windows 8-on. A lefordított EXE-t átviszem egy másik gépre, ahol nincs .NET 4.5 és ott is kiválóan fut! Nosza, használjunk valami spéci 4.5 feature-t:
static void Main(string[] args) { Console.WriteLine("Elindult."); Console.WriteLine("Méret: " + GetSize().Result ); Console.WriteLine("Vége."); Console.ReadLine(); } private static async Task<int> GetSize() { WebClient wc = new WebClient(); string content = await wc.DownloadStringTaskAsync(
new Uri(@"http://www.msdnkk.hu")); return content.Length; }
Ez .NET 4.5 híján is vidáman elindul, de futás közben elszáll:
W:\System\Desktop>VersionTest.exe Elindult. Unhandled Exception: System.TypeLoadException: Could not load type 'System.Runtime.CompilerServices.IAsyncStateMachine' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. at VersionTest.Program.GetSize() at VersionTest.Program.Main(String[] args)
Ez már nagyobb gond, hiszen senki sem szereti a futási idejű hibákat. Ha ez így van, akkor mégis mire jó a Project Properties ablakban a Target Framework opció?
Ha átállítod:
- Módosul a .csproj fájlban a <TargetFrameworkVersion> tulajdonság értéke, aminek megfelelően a lefordított DLL-ben a más lesz a szerelvény szintű TargetFramework attribútum értéke:
[assembly: TargetFramework(".NETFramework,Version=v4.5", FrameworkDisplayName = ".NET Framework 4.5")]
- Az app.config fájlban megváltozik a supportedRuntime elemben az sku attribútum értéke (webalkalmazás esetén a compilation elemben a targetFramework attribútum értéke):
<?xml version="1.0"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/> </startup> </configuration>
Vajon melyiket figyeli a runtime? A fenti példából egyértelműen látszik, hogy a .config fájlt. Ha nincs ott a konfig fájl, elindul az alkalmazás, és majd futási időben száll el. Ha ott van a konfig fájl, akkor el sem indul:
Itt a Yes-re kattintva jelenleg a .NET Framework 4.5 Beta letöltése kezdeményezhető a Microsoft Download Centerből.
Próbáljuk elkerülni a futási idejű hibát, azaz próbáljuk kitalálni futási időben, hogy milyen verzión futunk. A hagyományos megközelítés a verziószámok lekérdezése az Environment.Version tulajdonságon keresztül. Az eredmény:
- 4.0: 4.0.30319.544
- 4.5: 4.0.30319.17379
Szóval sem a major, sem a minor, sem a build verziószámra nem támaszkodhatunk, legfeljebb a revisionre. Arról pedig nem tudunk semmit, tehát a “nagyobb, mint 17000” jellegű megközelítések elég kockázatosak (még ha működnek is jelenleg).
Vessük be a JavaScriptből már jól ismert feature detection megközelítést, azaz ne a verziószámot ellenőrizzük, hanem azt tudjuk meg, hogy a funkció, amit használni akarunk, támogatott-e:
private static bool IsAsyncSupported() { return Type.GetType("System.Runtime.CompilerServices.IAsyncStateMachine",
false) != null; }
Majd:
if(IsAsyncSupported()) { Console.WriteLine("Méret: " + GetSize().Result); } else { Console.WriteLine("Frissíts 4.5-re!");
// Vagy ugyanez a funkció async nélkül megvalósítva...
}
Ez működik, de biztos, hogy ezt akarjuk?
Gyanítom, hogy lesznek ebből kellemetlenségeink. Íme egy kedves példa: most akkor a webalkalmazásunk milyen .NET verzión is fut (a .NET Framework version listában nincs is 4.5):
A példaprogramok végére miért jó odatenni a Console.ReadLine()-t?
Sose értettem…
Miért jó ennyit gépelni azért, hogy ne záródjon be a parancssor ablaka? Nem egyszerűbb nyomni Ctrl+F5-öt, vagy odarakni a helyére egy töréspontot?