470 likes | 652 Views
What’s new in Visual Studio 2010 and C# 4.0. Kirill Osenkov Visual Studio C# IDE Team. Language Features in C# 4.0. Dynamic Co-/Contravariance Named and Optional Arguments COM Interop Improvements. 1. Dynamic – Late Binding in C#. Early binding: Console .WriteLine(); Late binding:
E N D
What’s new in Visual Studio 2010 and C# 4.0 Kirill Osenkov Visual Studio C# IDE Team
Language Features in C# 4.0 • Dynamic • Co-/Contravariance • Named and Optional Arguments • COM Interop Improvements
1. Dynamic – Late Binding in C# Early binding:Console.WriteLine(); Late binding: typeof(Console).GetMethod("WriteLine").Invoke(null, null);
Static typing • Compiler checks members and types • IDE IntelliSense • Binding at compile time, exact method baked into IL call void [mscorlib]System.Console::WriteLine()
Dynamic typing • Member names, types and signatures not known at compile time • JavaScript, IronPython, IronRuby • COM Interop Scenarios • Reflection over non-accessible types • Compiler can’t check correctness • Refactoring doesn’t work
Starting Visual Studio // Type is not known at compile time Type vsType = Type.GetTypeFromProgID("VisualStudio.Dte.10.0"); // create an instance dynamically object instance = Activator.CreateInstance(vsType); // get the property and hope it's there PropertyInfo property = vsType.GetProperty("Visible"); // call and pass weakly typed arguments property.SetValue(instance, true, null);
Information in the code: // Type is not known at compile time Type vsType = Type.GetTypeFromProgID("VisualStudio.Dte.10.0"); // create an instance dynamically objectinstance = Activator.CreateInstance(vsType); // get the property and hope it's there PropertyInfo property = vsType.GetProperty("Visible"); // call and pass weakly typed arguments property.SetValue(instance, true, null);
Information in the code: • In this object, set the ‘Visible’ property to true
Expressing call information in code Type vsType = Type.GetTypeFromProgID("VisualStudio.Dte.10.0"); BEFORE: objectinstance = Activator.CreateInstance(vsType); PropertyInfoproperty = vsType.GetProperty("Visible"); property.SetValue(instance, true, null); AFTER: dynamicinstance = Activator.CreateInstance(vsType); instance.Visible = true;
How it works instance.Visible = true;
How it works … becomes …
How it works if (<StartVSDynamic>o__SiteContainer0.<>p__Site1 == null) { <StartVSDynamic>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, bool, object>>.Create(Binder.SetMember(CSharpBinderFlags.None, "Visible", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.Constant | CSharpArgumentInfoFlags.UseCompileTimeType, null) })); } <StartVSDynamic>o__SiteContainer0.<>p__Site1.Target.Invoke(<StartVSDynamic>o__SiteContainer0.<>p__Site1, instance, true);
Details • A DLR callsite object is created upon first request • All the statically known callsite information is encapsulated • Callsites are cached for performance
Bonus abstraction layer • A way to intercept dynamic calls and plug in your own behavior • DynamicObject, IDynamicMetaObjectProvider • TryGetMember, TrySetMember get called when a member is called on the dynamic object • ExpandoObject
Dynamic sample: Dictionary colors.Blue instead of colors["Blue"] colors.Red = 0xFF0000; instead of colors.Add("Red", 0xFF0000);
Dynamic sample: XML customer.Address.Street instead of customer.Element(“Address”).Attribute(“Street”).Value
Dynamic sample: XML dynamic contact = new DynamicXMLNode("Contacts"); contact.Name = "Patrick Hines"; contact.Phone = "206-555-0144"; contact.Address = new DynamicXMLNode(); contact.Address.Street = "123 Main St"; contact.Address.City = "Mercer Island"; contact.Address.State = "WA"; contact.Address.Postal = "68402";
Dynamic Sample: Reflection • Before: var employee = newEmployee();var members = employee.GetType().GetMember("age", MemberTypes.All, BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);((FieldInfo)members[0]).SetValue(employee, 42); • After: dynamic employee = (newEmployee()).AsDynamic();employee.Age = 42;
2. Co/Contravariance • This feature is very hard to explain • You only need it once a month or less • When you do need it you do need it • It’s about passing around generic interfaces and delegates only • Whatever you’d expect should work now works
IN and OUT: publicWidget CreateWidget(string name); “OUT” “IN”
Fails in C# 3: using System; classProgram { staticvoid Main(string[] args) { Func<string> stringFactory = () => "Hello"; Print(stringFactory); } staticvoid Print(Func<object> objectFactory) { object o = objectFactory(); Console.WriteLine(o); } }
Works in C# 4: using System; classProgram { staticvoid Main(string[] args) { Func<string> stringFactory = () => "Hello"; Print(stringFactory); } staticvoid Print(Func<object> objectFactory) { object o = objectFactory(); Console.WriteLine(o); } } Func<object> object covariance string Func<string>
out == covariant • Func is covariant in TResult • All about “producing” types • Func<T>, IEnumerable<T>, *Factory, *Creator • Covariant interfaces and delegates in the BCL are annotated with ‘out’ publicdelegate TResult Func<out TResult>();
Fails in C# 3: using System; classProgram { staticvoid Main(string[] args) { Action<object> objectPrinter = Console.WriteLine; PrintHello(objectPrinter); } staticvoid PrintHello(Action<string> printer) { printer("Hello"); } }
Works in C# 4: using System; classProgram { staticvoid Main(string[] args) { Action<object> objectPrinter = Console.WriteLine; PrintHello(objectPrinter); } staticvoid PrintHello(Action<string> printer) { printer("Hello"); } } Action<object> object contravariance string Action<string>
in == contravariant • Action is contravariant in T • All about “consuming” types: Action<T>, IComparer<T> • Contravariant interfaces and delegates in the BCL are annotated with ‘in’ publicdelegatevoidAction<in T>(T obj);
Co/Contravariant BCL Types • Covariance (“out”): • IEnumerable<Animal> is now assignable from IEnumerable<Cat> • Func<Cat> is now also a Func<Animal> • Contravariance (“in”): • A variable of type Action<Cat> (specific) can now be assigned a value of type Action<Animal>(generic) • http://msdn.microsoft.com/en-us/library/dd799517.aspx
Named arguments document.Close(saveChanges: true);vs. document.Close(true); • Arguments can now be specified out of order • Code readability is improved • Warning: parameter names become part of API • Renaming a parameter in one assembly can now break the code in another assembly
Optional arguments • Before: var app = newApplication();var missing = Type.Missing;object fileName = "word.doc";app.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
Optional arguments • After: var app = newApplication();app.Documents.Open("word.doc");
COM improvements • Omit ref • No PIA • Indexed properties
Omit ref on COM arguments • app.Documents.Close(missing);instead of • app.Documents.Close(ref missing);
No PIA (Primary Interop Assemblies) • PIAs are managed wrapper assemblies around COM types: EnvDTE, Microsoft.Office.Interop.Word, etc. • Can embed the necessary parts in your program • PIA doesn’t need to be distributed with your app
Indexed Properties • Before: excel.get_Range("A1").set_Value(Type.Missing, "ID"); • After: excel.Range["A1"].Value = "ID";
Event implementation changes • Before: [MethodImpl(MethodImplOptions.Synchronized)] public void add_MouseDown(Action value) { this.MouseDown = (Action) Delegate.Combine(this.MouseDown, value); }
Event implementation changes • After: public static void add_MouseDown(Action value) { Action action2; Action MouseDown = MouseDown; do { action2 = MouseDown; Action action3 = (Action) Delegate.Combine(action2, value); MouseDown = Interlocked.CompareExchange<Action> (ref MouseDown, action3, action2); } while (MouseDown != action2); }
C# IDE Features • Ctrl+, • Ctrl+K,T • Ctrl+Shift+Up/Down • Ctrl+. • Ctrl+Alt+Space
C# IDE Features • Navigate To • Call Hierarchy • Highlight References • Generate From Usage • IntelliSense improvements (consume-first, sub-string and camelCase search)
Q & A • Kirill Osenkov • http://blogs.msdn.com/b/kirillosenkov • http://twitter.com/kirillosenkov
Team Architect • Architecture Explorer • Sequence Diagrams • DGML – graph modeling
Debugger • IntelliTrace • Pinnable Data Tips • Thread Window improvements (Freeze/thaw) • Parallel Debugging tool windows
Shell • WPF Shell • Multi-monitor support • Extension Manager
Editor • Brand new WPF text editor • Box-selection • Zoom, Ctrl+scroll
Shameless Plug: • My open-source projects: • http://livegeometry.codeplex.com • http://undo.codeplex.com • http://structurededitor.codeplex.com • http://layout.osenkov.com