Posts tagged with c - page 9

Object Initializers in .NET 3.5

One compiler improvement in .NET 3.5 is the object initializers feature that lets you concisely set properties of an object as you create it.

If you’ve ever used VB.NET you may well have found and enjoyed the with keyword to write code such as:

Dim myObj As MyClass
myObj = New MyClass()
With myObj
  .ProductCode = "ABC123"
  .Quantity = 5
  .Cost = 567.89
End With

This is more concise than writing myObj several times over, especially if setting a large number of properties, but as C# has no such keyword many people resorted to providing helpful constructors to facilitate code like:

MyClass myObj = new MyClass("ABC123", 5, 567.89);

If all three of these properties are essential then this makes for a sensible constructor however many classes have a number of properties that are optional and class designers struggle to determine whether to make constructors that merely cut-down on typing and which of the various combinations of optional properties might make sense in having their own constructor.

Invariably the combination you might want doesn’t exist and if it does the chances of being able to understand which properties are being set from one of a number of constructors that take parameters of similar types is quite low unless you go and take a peek with the IntelliSense.

Using object initializers you can stick to creating constructors that reflect parameters necessary to ensure your object is in a valid state and forget about providing helpful ones for those optional parameters. In our example if we assume the ProductCode is essential and the others are optional we can write code like:

MyClass myObj = new MyClass("ABC123") { Quantity = 5, Cost = 567.89 };

Which is both concise and easy to understand. It also requires no work on the part of the class designer and therefore works with all your existing classes. You can also nest them to set properties that require more complex types such as:

MyClass myObj = new MyClass("ABC123") {
   Quantity = 5,
   Cost = 567.89,
   Category = new Category("A") { Description = "New machine" }
};

This feature is no use if your objects are immutable in which case constructors are your only friend.

[)amien

Extension methods illustrated

Extension methods are a great new feature in the .NET Framework 3.5 that let you write new methods that appear to be part of existing classes without the need to subclass or modify them.

We can explain this in simple terms with an example. Here is a useful routine that takes a string and returns what it finds between two other strings that works just fine with .NET 2.0 and .NET 1.1.

public static string Between(string value, string start, string end) {
  int startIndex = value.IndexOf(start, StringComparison.CurrentCultureIgnoreCase);
  if (startIndex == -1)
    return "";
  startIndex += start.Length;

  int endIndex = value.IndexOf(end, startIndex, StringComparison.CurrentCultureIgnoreCase);
  if (endIndex == -1)
    return "";

  return value.Substring(startIndex, endIndex-startIndex);
}

If this method belonged to a static StringUtilities class then you could use it like this:

string newString = StringUtilities.Between(inputString, startingString, endingString);

The problem is knowing that the StringUtilities class within the project you are working on and until you know that IntelliSense can’t even kick in. What would be nice is to add this to the String class but of course we can’t because String is sealed and besides methods everywhere create String classes and not instances of your subclass.

What would be really cool is if Visual Studio and .NET could just realize that this method is static and takes a string parameter as it’s first parameter and let it just appear as another method on the String class and just call StringUtilities behind the scenes.

That is exactly what the extension methods in .NET 3.5 achieve.

All we need to do is put this in front of the first parameter which will let VS and the compiler know that this method should appear as if it is a method against the type of that first parameter. The method must be static and visible to the code and curiously the class itself must also be static. Our signature now appears as:

public static string Between(string <em>this</em> value, string start, string end)

To call the method we simply press . after our string and IntelliSense displays all the usual methods and properties of the String class and any extension methods it can find in your project too which now includes our Between method giving us:

string newString = inputString.Between(startingString, endingString);

Nice but bear in mind the extension method can only access the public parts of the class it will appear with – there is no privileged access to protected properties or methods that would be available with sub-classing!

[)amien

Refactoring shared libraries and public APIs

Refactoring is an essential process to keep code clean and elegant while it evolves. IDE’s offer common refactorings (although somewhat short of those prescribed in Fowler’s excellent Refactoring book and way short of the overall goals explained in Kerievsky’s Refactoring Patterns).

One limitation of existing tools is that they can only update references within your solution. When you are refactoring a shared library this is a problem, especially if it is your public API to the outside world.

We need to introduce metadata to document how the API has evolved and extend the tools to generate and understand this metadata.

Let’s take a look at a few of the refactoring in Visual Studio and see how they could be documented using the .NET metadata mechanism of choice, attributes.

Rename

Starting simple lets we had a property named Reference:

public string Reference {
  get { return id; }
}

We are going to rename Reference to StockCode for the 1.1.0.0 release. The tool could introduce a stub for backward compatibility whilst also marking it with metadata giving us:

[DeprecatedRefactorRename("StockCode", "1.1.0.0")]
public string Reference {
  get { return StockCode; }
}

public string StockCode {
  get { return id; }
}

The library is both binary and source compatible but with a little IDE work they could get a warning that Reference is now StockCode and given the choice of updating all the references in their project.

Nice. Let’s try a few more:

Remove Parameters

public bool AddStock(int quantity, DateTime arrival, StorageBin location) {
   ...
}

We are switching to a managed warehouse and so we no longer need to know where items are stored so we refactor and remove the StorageBin.

[DeprecatedParameterRemoved("location", "1.1.0.0.")]
public bool AddStock(int quantity, DateTime arrival, StorageBin location) {
  return AddStock(quantity, arrival);
}

public bool AddStock(int quantity, DateTime arrival) {
  ...
}

Reorder Parameters

[DeprecatedParametersReordered("arrival, quantity", "1.1.0.0.")]
public bool AddStock(int quantity, DateTime arrival) {
  return AddStock(arrival, quantity);
}

public bool AddStock(DateTime arrival, int quantity) {
  ...
}

Move Method

Existing tools offer little support for MoveMethod because they haven’t considered how to refactor the references. It is difficult to retain binary compatibility unless the class has a reference to class that now has the method we are interested in.

[DeprecatedMethodMoved("StockController", "Add", "1.1.0.0")]
public bool AddStock(DateTime arrival, int quantity) {
  return stockController.Add(this, arrival, quantity);
}

Let’s say the current calling code looks something like:

stockController.DoSomething();
selectedProduct.AddStock(DateTime.Now, input.Value);

However with a little ingenuity the IDE could examine the new method and map existing parameters based on name and type. If it still doesn’t have enough information consider local variables and properties of the objects it does have to present choices. This works especially well if your parameters are not primitives. Our code becomes:

stockController.DoSomething();
stockController.Add(selectedProduct, DateTime.Now, input.Value);

Keeping it clean

We don’t want our classes being cluttered with deprecated code indefinitely so the solution should contain two extra revision numbers, one detailing the oldest revision of attributes to keep in the source, the other for the oldest revision to compile into the binary. All the [Deprecated] marked methods and properties can slip into another file, perhaps Product.deprecated.cs so they stay out of sight until needed.

For .NET it would need somebody at Microsoft to take this on board and move us forward from ObsoleteAttribute as the facility should be cross-tool and so adding it solely to SharpDevelop would be of limited gain.

[)amien

LINQ in 60 seconds

Microsoft’s Language INtegrated Query (LINQ) aims to provide a way of selecting objects with a common syntax independent of the data source.

By integrating query into the language instead strings parsed by an external provider at runtime we gain IntelliSense prompting for fields, members and table names and full compile-time syntax checking and a unified syntax.

They will be included in the .NET Framework 3.5 and delivered as part of the Visual Studio 2008 ‘Orcas’ release which is currently available in beta and comprises of:

LINQ syntax

The language extensions themselves. An example in C# might look like:

GridView1.DataSource = from country in countries
                       where country.Continent == 'Europe'
                       orderby population descending
                       select country;

LINQ to Objects

A core part of the .NET Framework 3.5 and allows you to query against any IEnumerable collection and test or sort against any of T’s properties.

In the above example imagine Country is a business class and Countries is a List. Continent is a string property and population a numeric one.

LINQ to SQL (formerly known as DLinq)

LINQ to SQL works by mapping classes and properties to tables and fields as any normal Object-Relational Mapping (ORM) tool would.

It achieves this by marking the classes and properties with attributes to indicate how they map to the underlying database. A visual modeling tool is provided that can generate and manipulate such classes for you from an existing SQL database.

The ORM functionality includes tracking of changed objects and change persistence. It also ensures that you will not obtain multiple objects for the same underlying row in the database (Fowler’s Identity Map).

Other components

There are many other components in the LINQ family including:

LINQ to XML (formerly known as XLinq)

Similar to LINQ to SQL but along the idea of querying XML documents using LINQ syntax rather than the XPath/XQuery syntax.

LINQ to Entities (ADO.NET Entities)

A more advanced ORM solution that allows more extensive mapping and manipulation between how the object appears and the underlying data source.

Third-party support

Mono is actively implementing LINQ as are the people behind the NHibernate ORM.

[)amien