Protože v posledním dílu jsme nakousli nové možnosti v jazyku C#, bude dobré dnes v tomto pokračovat. Představíme si nové klíčové slovo – dynamic.
reklama
Protože v posledním dílu jsme nakousli nové možnosti v jazyku C#, bude dobré dnes v tomto pokračovat. Představíme si nové klíčové slovo – dynamic.
Typ dynamic je statický typ, jehož „možnosti“ jsou zkoumány až za běhu. Velmi jednoduše tak zajistíte elegantní spolupráci C# kódu s IronPythonem, COM objekty či pouhé reflection.
Je důležité si uvědomit, že dynamic je stále statický typ. C# se tedy nastává plně dynamickým jazykem. A každý objekt může být implicitně do typu dynamic přetypován, můžeme-li v tomto případě o přetypování tak jak jej známe mluvit. Nad dynamickým typem je možné provádět všechny operace, které nyní používáme – volání metod, přístup k prvkům a vlastnostem, použití indexem i použití jako volání delegáta.
Podívejme se na několik příkladů:
static void Main(string[] args)
{
dynamic f = new Foo();
f.Bar = 10;
f.Baz = "20";
int i = f.Do("x");
Console.WriteLine(i);
}
class Foo
{
public int Bar { get; set; }
public string Baz { get; set; }
public int Do(string s)
{
return this.Bar;
}
}
Pokud si tento kód spustíte, vše bude fungovat jako by typ byl určen přímo. Možná zde stojí za to, poznamenat, že veškeré vlastnosti, metody atd. objektu jsou zjišťovány až skutečně za běhu (včetně například výběru overload metody). Nejedná se tedy jen o vynechání typu, který je automaticky odvozen, jako v případě použití klíčového slova „var“. Můžete se o tom mimo jiné přesvědčit tím, že nefunguje IntelliSense – Visual Studio zkrátka neví, jaký typ se v proměnné opravdu objeví (bez ohledu na to, že v této ukázce je to zřejmé).
Upravíme-li kód přidáním řádku, kde zavoláme metodu se špatnými parametry (nebo třeba neexistující), program se stále bez problému zkompiluje a spustí, avšak skončí s chybou (pokud by bylo použité klíčové slovo „var“ kompilátor by kód ani nepřeložil).
static void Main(string[] args)
{
dynamic f = new Foo();
f.Bar = 10;
f.Baz = "20";
int i = f.Do("x");
Console.WriteLine(i);
f.Do(DateTime.Now);
}
A výsledkem je výjimka Microsoft.CSharp.RuntimeBinder.RuntimeBinderException.
Pokud píšete výhradně staticky typovaný C# kód, může vám zavedení tohoto konstruktu připadat postavené na hlavu a spíše možnosti ubírající. Opak je však pravdou, leží však trochu pod povrchem. Jako příklad si vezměme spouštění kódu z načteného assembly. Pokud jste neměli alespoň interface pro vámi používanou třídu, práce to nebyla opravdu lehká.
Assembly a = Assembly.LoadFile(Path.GetFullPath(@"..\..\..\DummyLib\bin\Debug\DummyLib.dll"));
object myClass = a.CreateInstance("DummyLib.MyClass");
Type myClassType = myClass.GetType();
DateTime dt = (DateTime)myClassType.InvokeMember("SomeDate", BindingFlags.InvokeMethod, null, myClass, new object[] { });
Console.WriteLine(dt.ToShortDateString());
Psaní takového kódu je nejen neproduktivní, ale také velmi obtížné na jakékoli další úpravy, neboť se jednak špatně čte a jednak je velké množství položek zapsána jako řetězce. V kontrastu použití dynamic:
Assembly a = Assembly.LoadFile(Path.GetFullPath(@"..\..\..\DummyLib\bin\Debug\DummyLib.dll"));
dynamic myClass = a.CreateInstance("DummyLib.MyClass");
DateTime dt = myClass.SomeDate();
Console.WriteLine(dt.ToShortDateString());
O vítězi myslím není třeba hlasovat. A při použití s Pythonem již téměř není poznat rozdíl mezi staticky typovaným C# a dynamickým Pythonem. A tím samozřejmě zábava nekončí. Použití COM objektů nikdy nebylo jednodušší.
Pokud je do dynamic proměnné přiřazen COM objekt, operace jsou následně přes COM IDispatch. Takže i pokud k danému objektu nejsou dostupné PIA (Primary Interop Assemblies), není to sebemenší problém (a je samozřejmě též možné využívat vlastností COM světa, které neexistují v C#).
Možná vás napadla otázka: „Jak je to celé řešeno.“. Vězte, že jako podvozek slouží tzv. Dynamic Language Runtime (DLR). Pokud vás toto téma zajímá hlouběji, doporučuji podívat se na věci kolem rozhranní IDynamicObject a také na seriál zde na vyvojar.cz.
Stejně jako u ko- a kontravariance i při používání dynamic můžeme nalézt několik omezení, která vás při používání v C# mohou „zastihnout“. Pravděpodobně nejbolestivějším je nemožnost používat extension metody. Dynamické hledání je prostě nedokáže najít. A stejně tak použití anonymních metod jako argumenty metody není možné. Kompilátor prostě neví, jaký typ má použít, když neví typ je cílový. Leč je pravděpodobné, že další verze jazyka tato omezení odstraní.