Published: 04 Jan 2010
By: Manning Publications

This article is taken from the book C# in Depth, Second Edition.

Contents [hide]

About the book

This is a sample chapter of the book C# in Depth, Second Edition. It has been published with the exclusive permission of Manning.


Written by: Jon Skeet
Pages: 500
Publisher: Manning
ISBN: 9781935182474

Get 30% discount

DotNetSlacker readers can get 30% off the full print book or ebook at www.manning.com using the promo code dns30 at checkout.

Dynamic Binding in a Static Language, Part 1 Series

  • Part 1 Dynamic Binding in a Static Language, Part 1
  • Part 2 Dynamic Binding in a Static Language, Part 2
  • Introduction

    In the first part of this article, we looked at what it meant for code to be dynamic, and the syntax involved in using dynamic typing in C# 4. In this part we're going to look at some examples of using it to interoperate with other platforms.

    Dynamic typing is a little bit like unsafe code, or interoperability with native code using P/Invoke. Many developers will have no need for it, or use it once in a blue moon. For other developers - particularly those dealing with Microsoft Office - it will be give a huge productivity boost, either by making their existing code simpler or by allowing radically different approaches to their problems.

    This article is not meant to be exhaustive by any means, and I look forward to seeing innovative uses of dynamic typing from C# in the coming years. Will unit testing and mocking take a big step forward with new frameworks? Will we see dynamic web service clients, accessing RESTful services with simple member access? I'm not going to make any predictions, other than that it'll be an interesting area to keep can eye on.

    We're going to look at two examples: working with Excel, and calling into Python.

    COM in general, and Microsoft Office in particular

    If you choose to embed the interop types you're using into the assembly (by using the /link compiler switch, or setting the "Embed Interop Types" property to True) then anything in the API which would otherwise be declared as object is changed to dynamic. This makes it much easier to work with somewhat weakly typed APIs such as those exposed by Office. (Although the object model in Office is reasonably strong in itself, many properties are exposed as variants as they can deal with numbers, strings, dates and so on.) I'll just show you just a short example here; the dynamic aspect is very easy to understand from just this one scenario. We're going to set the first twenty cells of the top row of a new Excel worksheet to the numbers 1 to 20. Listing 1 shows an initial, statically typed piece of code to achieve this.

    Listing 1: Setting a range of values with static typing

    This time we've imported the Microsoft.Office.Interop.Excel namespace - so the Application type refers to Excel, not Word. We're still using the new features of C# 4, by not specifying an argument for the optional parameter in the Workbooks.Add() call while we're setting things up and also by using a named indexer . When Excel is up and running, we work out the start and end cells of our overall range. In this case they're both on the same row, but we could have created a rectangular range instead by selecting two opposite corners. We could have created the range in a single call to Range["A1:T1"] but I personally find it easier to work with numbers consistently. Cell names like B3 are great for humans, but harder to use in a program.

    Once we've got the range, we set all the values in it by setting the Value2 property with an array of integers . We can use a one-dimensional array as we're only setting a single row; to set a range spanning multiple rows we'd need to use a rectangular array. This all works, but we've had to use three casts in six lines of code. The indexer we call via Cells and the ActiveSheet property are both declared to return object normally. (Various parameters are also declared as type object, but that doesn't matter as much because there's an implicit conversion from any non-pointer type to - it's only coming the other way object that requires the cast.) For simplicity's sake I haven't closed Excel at the end of the listing - it's easier to just see the open worksheet than to save it to a file in code, close the application, and then load up the file separately to check that it's worked.

    With the Primary Interop Assembly set to embed the required types into our own binary, all of these examples become dynamic. With the implicit conversion from to any other type, we can just remove all the casts, as shown in dynamic listing 2.

    Listing 2: Using implicit conversions from dynamic in Excel

    This really is exactly the same code as listing 14.5 but without the casts. However, it's worth noting that the conversions are still checked at execution time. If we changed the declaration of start to be Worksheet, the conversion would fail and an exception would be thrown. Of course, you don't have to perform the conversion. You could just leave everything as dynamic, as shown in listing 3:

    Listing 3: Using dynamic everywhere

    Which is clearer? Well, I'm an old-fashioned static typing fan, so I prefer the previous version. It states the types I expect on each line, so if there are any problems I get to find out immediately rather than waiting until I try to use a value in a way which may not be supported. In terms of productivity when initially developing, there are pros and cons both ways - using dynamic, I don't need to work out which particular type I really expect; I can just use the value and so long as all the necessary operations are supported, I'm okay. On the other hand, using static typing I can see what's available at every stage via IntelliSense. We're still using dynamic typing of course, to provide the implicit conversion to Worksheet and Range - we're just using it for one step at a time rather than wholesale. The change from static typing to dynamic may not look like much to start with because the example is relatively simple - but as the complexity of the code increases, so does the readability benefit of removing all those casts.

    In some ways this has all been a blast from the past - COM is a relatively old technology. Now we're going to jump to interoperating with something much more recent: IronPython.

    Dynamic languages such as IronPython

    In this section I'm only going to use IronPython as an example, but of course that's not the only dynamic language available for the DLR. It's arguably the most mature, but there are already alternatives such as IronRuby and IronScheme. One of the stated aims of the DLR is to make it easier for budding language designers to create a working language which has good interoperability with other DLR languages and the traditional .NET languages such as C#, as well as access to the huge .NET framework libraries.

    Why would I want to use IronPython from C#?

    There are many reasons one might want to interoperate with a dynamic language, just as it's been beneficial to interoperate with other managed languages from .NET's infancy. It's clearly useful for a VB developer to be able to use a class library written in C# and vice versa - so why would the same not be true of dynamic languages? I asked Michael Foord, the author of Iron Python in Action, to come up with a few ideas for using IronPython within a C# application. Here's his list:

    • User scripting
    • Writing a layer of your application in IronPython
    • Using Python as a configuration language
    • Using Python as a rules engine with rules stored as text (even in a database)
    • Using a Python library such as feedparser
    • Putting a live interpreter into your application for debugging

    If you're still skeptical, you might want to consider that embedding a scripting language in a mainstream application is far from uncommon - indeed, Sid Meier's Civilization IV computer game is scriptable with Python. This isn't just an afterthought for modifications, either - a lot of the core gameplay is written in Python: once they'd built the engine the developers found it to be a more powerful development environment than they'd originally imagined.

    NOTE

    Or way of life, depending on how you view the world and your level of addiction to playing the game.

    For this article, I'm going to pick the single example of using Python as a configuration language. Just as with the COM example, I'm going to keep it very simple, but hopefully it'll provide enough of a starting point for you to experiment more with it if you're interested.

    Getting started: embedding "hello, world"

    There are various types available if you want to host or embed another language within a C# application, depending on the level of flexibility and control you want to achieve. We're only going to use ScriptEngine and ScriptScope, because our requirements are quite primitive. In our example we know we're always going to use Python, so we can ask the IronPython framework to create a ScriptRuntime directly; in more general situations you can use a ScriptRuntime to pick language implementations dynamically by name. More demanding scenarios may require you to work with ScriptHost and ScriptSource, as well as using more of the features of the other types too.

    Not content with merely printing "hello, world" once, our initial example will do so twice, first by using text passed directly into the engine as a string, and then by loading a file called HelloWorld.py. Listing 4 shows everything you need.

    Listing 4: Printing "hello, world" twice using Python embedded in C#

    You may find this listing either quite dull or very exciting, both for the same reason. It's simple to understand, requiring very little explanation. It does very little, in terms of actual output... and yet the fact that it is so easy to embed Python code into C# is a cause for celebration. True, our level of interaction is somewhat minimal so far - but it really couldn't be much easier than this.

    Python's many string literal forms

    The Python file contains a single line: print "hello, world" - note the double quotes in the file compared with the single quotes in the string literal we passed into engine.Execute(). Either would have been fine in either source. Python has various string literal representations, including triple single quotes or triple double quotes for multi-line literals. I only mention this because it's very useful not to have to escape double quotes any time you want to put Python code into a C# string literal.

    The next type we need is ScriptScope, which will be crucial to our configuration script.

    Storing and retrieving information from a ScriptScope

    The execution methods we've used both have overloads with a second parameter - a scope. In its simplest terms, this can be regarded as a dictionary of names and values. Scripting languages often allow variables to be assigned without any explicit declaration, and when this is done in the top level of a program (instead of in a function or class) this usually affects a global scope. When a ScriptScope instance is passed into an execution method, that is the global scope for the script you've asked the engine to execute. The script can retrieve existing values from the scope, and create new values, as shown in listing 5.

    Listing 5: Passing information between a host and the hosted script using ScriptScope

    I've embedded the Python source code into the C# code as a verbatim string literal rather than putting it in a file, so that it's easier to see all the code in one place. I don't recommend that you do this in production code, partly because Python is sensitive to whitespace - reformatting the code in a seemingly-harmless way can make it fail completely at execution time.

    The SetVariable and GetVariable methods simply put values into the scope and fetch them out again in the obvious way. They're declared in terms of object rather than dynamic, as you might have expected. However, GetVariable also allows you to specify a type argument, which acts as a conversion request. This is not quite the same as just casting the result of the nongeneric method, as the latter just unboxes the value - which means you need to cast it to exactly the right type. For example, we can put an integer into the scope, but retrieve it as a double:

    The first call succeeds: we're explicitly telling GetVariable what type we want, so it knows to coerce the value appropriately. The second call will throw an InvalidCastException, just as it would in any other situation where you try to unbox a value using the wrong type.

    The scope can also hold functions which we can retrieve and then call dynamically, passing arguments and returning values. The easiest way of doing this is to use the dynamic type, as shown in listing 6.

    Listing 6: Calling a function declared in a ScriptScope

    Configuration files may not often need this ability, but it can be useful in other situations. For example, you could easily use Python to script a graph-drawing program, by providing a function to be called on each input point. There are a number of situations in which it's useful to have some sort of "expression evaluator" running user code entered at execution time, such as evaluating business rules for discounts, shipping costs and so on. It can be useful to be able to change these rules in text form without having to recompile or redeploy binaries.

    Putting it all together

    Now that we can get values into our scope, we're essentially done. We could potentially wrap the scope in another object providing access via an indexer - or even access the values dynamically using DynamicObject. The application code might look something like this:

    The exact form of the Configuration type will depend on your application, but it's unlikely to be terribly exciting code. I've provided a sample dynamic implementation in the full source, which allows you to retrieve values as properties and call functions directly too. Of course we're not limited to just using primitive types in our configuration: the Python code could be arbitrarily complex, building collections, wiring up components and services and so forth. Indeed, it could perform a lot of the roles of a normal Dependency Injection or Inversion of Control container.

    The important thing is that we now have a configuration file which is active instead of the traditional passive XML and .ini files. Of course, you could have embedded your own programming language into previous configuration files - but the result would probably have been less powerful, and would have taken a lot more effort to implement. As an example of where this could be useful in a simpler situation than full dependency injection, you might want to configure the number of threads to use for some background processing component in your application. You might normally use as many threads as you have processors in the system, but occasionally reduce it in order to help another application run smoothly on the same system. The configuration file would simply change from something like this:

    To this:

    This change wouldn't require the application to be rebuilt or redeployed - just edit the file and restart the application. Particularly smart applications could even choose to reconfigure themselves on the fly. (I've usually found that this ability is more painful to implement than the extra value it brings, but in certain places it can make a big difference. The ability to change logging levels either for a particular bit of code or even just a specific user who's having difficulties can make debugging much easier.)

    Other than executing functions, we haven't really looked at using Python in a particularly dynamic way. The full power of Python is available, and using the type in your C# code you can take advantage of meta-programming and dynamic all the other dynamic features. The C# compiler is responsible for representing your code in an appropriate fashion, and the script engine is responsible for taking that code and working out what it means for Python. Just don't feel you have to be doing anything particularly clever for it to be worth embedding the script engine in your application. It's a simple step towards a more powerful application.

    One caveat around dynamic execution like this: if you're executing arbitrary code, particularly code entered by external users of the system, you should think very seriously about security, and quite possibly run the script in some sort of sandboxed environment. Discussion of this topic is outside the scope of this article, but it needs to be considered carefully.

    Conclusion

    There's much more to dynamic typing of course - including uses within C# which don't have anything to do with interoperability. I hope this article has given you a taste of the possibilities - have fun exploring the dynamic world in your own code!

    Dynamic Binding in a Static Language, Part 1 Series

  • Part 1 Dynamic Binding in a Static Language, Part 1
  • Part 2 Dynamic Binding in a Static Language, Part 2
  • Get 30% discount

    DotNetSlacker readers can get 30% off the full print book or ebook at www.manning.com using the promo code dns30 at checkout.

    <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Manning Publications

    Manning Publication publishes computer books for professionals--programmers, system administrators, designers, architects, managers and others. Our focus is on computing titles at professional levels. We care about the quality of our books. We work with our authors to coax out of them the best writi...

    This author has published 33 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    C# 4.0 Reflection Programming - Part 3
    In the previous article, we used the reflection to obtain the information of an assembly, module, ty...
    C# 4.0 Reflection Programming - Part 4
    In this last article of this series, we will learn what to do with reflection. But before making the...
    C# 4.0 Reflection Programming - Part 2
    As introduced in the first article, the most typically-used tools associated with .NET reflection ar...
    Understanding and Using Extension Methods
    Extension methods were new to C# 3.0. They allow you to add a method to an existing type without hav...
    Introduction to C# 3.0 features
    C# 3.0 introduced some of very useful features built on top of 2.0. This article explains the usage,...

    You might also be interested in the following related blog posts


    Html Encoding Nuggets With ASP.NET MVC 2 read more
    Dynamic in C# 4.0: Introducing the ExpandoObject read more
    My History of Visual Studio (Part 6) read more
    Dynamic in C# 4.0: Creating Wrappers with DynamicObject read more
    Fun With Method Missing and C# 4 read more
    "Future Directions for Visual Basic" by Anders Hejlsberg and Jonathan Aneja read more
    Fun with C# 4.0s dynamic read more
    F# in VS2010 read more
    My History of Visual Studio (Part 5) read more
    Dynamic Languages: A Separation of Concerns read more
    Top
     
     
     

    Discussion


    Subject Author Date
    placeholder Good Explanation Anil Pandey 1/7/2010 12:51 AM

    Please login to rate or to leave a comment.