Friday, January 26, 2007

Playing with attributes

I'm sure by now you've seen all sorts of .NET framework attributes that can be applied to various pieces of code. The most notable of these in my code are FlagsAttribute (for enums), and the XML serialization / Web Services ones (XmlElementAttribute, XmlAttributeAttribute, etc., and WebServiceAttribute). These are very nice and unleash all kinds of built-in behavior in the framework, but did you know you can make your own attributes and use them for your own purposes? That's what this blog entry is all about!

For me, one of the most common problems I face is one in which I would like to use an enumeration for a class member that has a list of choices. Of course, this is a no-brainer to use an enum for this, but often I want to go one step further. Often, I'd like to limit the enum's choices for the class member, based on the value of one or more of the other class members. This problem is very common in heirarchies where you have a shared base class that you want to support a member in that can have values that aren't always applicable to the object.

Let's say for the sake of argument that you have a class A with members x, y, and z. The z member should be a choice of z1, z2, or z3, but each of these choices is only available when the following conditions hold:


ConditionAvailability
x > 0, y anythingz1 z2 available, z3 not
x = 0, y > 0z1 available, z2, z3 not
x = 0, y < 0z2 available, z1, z3 not
x < 0, y anythingz3 available, z1, z2 not

We can see that these rules can be distilled into a separate "test function" for each value of z. For z1, it's available if x>0 (x == 0 && y>0). For z2, it's available if x>0 (x == 0 && y<0). For z3, it's available if x<0 only.

Now, I crashed my compiler in the process of trying to use anonymous delegates to express these conditions. Unfortunately, that doesn't seem to work. However, we can package these three tests into a helper class that provides static methods to perform these tests. For instance, let's make a class ZValueTests as follows:

  public static class ZValueTests
{
public static bool TestForZ1(int x, int y)
{
return x>0 (x == 0 && y>0);
}

public static bool TestForZ2(int x, int y)
{
return x>0 (x == 0 && y<0);
}

public static bool TestForZ3(int x, int y)
{
return x<0;
}
}

Now that we have these tests, we can use them in an attribute that we apply to each of our enum values. Let's first define our attribute class. We'll call it ValidForAttribute, and it must derive from the Attribute class to be known by the compiler. We'll have to use reflection to call the test functions, so this will be a fun demo in many ways! Here's our attribute declaration.

  [AttributeUsage(AttributeTargets.Field)]
public class ValidForAttribute : Attribute
{
private SR.MethodInfo _Test;

public ValidForAttribute(
Type TestClass,
string MethodName)
{
SR.MethodInfo mi
= TestClass.GetMethod(MethodName);
// assertions omitted for brevity
_Test = mi;
}

public bool Test(int x, int y)
{
return (bool)_Test.Invoke(
null,
new object[] { x, y });
}
}

As you can see from the declaration, we'll need to specify our attribute using the type of the class that implements our tests, and the name of the method on that class. This is because we can't use non-constant expressions in the attribute initializer (a pretty big limitation if you ask me), so we can't even use delegate creation expressions, much less anonymous methods! Anyway, this works, it's just a little less pleasant than I would have liked.

Now, we need to declare our actual Enum. You'll see it will be very easy and will look something like the following:

  public enum ZValue
{
[ValidFor(typeof(ZValueTests), "TestForZ1")]
z1,
[ValidFor(typeof(ZValueTests), "TestForZ2")]
z2,
[ValidFor(typeof(ZValueTests), "TestForZ3")]
z3
}

This is very pleasant as it very clearly defines the test functions that apply to each z value. Of course, one unpleasant thing is that the types of these functions cannot be checked until runtime (that's what the asserts that are omitted from the code in the attribute do). I would recommend even throwing an exception if the function isn't declared right from the constructor of the attribute, but that may be a bit harsh.

Now, I've shown how you can declare the enums, attribute class, and test class - but what we really want to see is the validation in action, right? So, here we go. If we declare the class A as follows:

public class A {
ZValue _z;

bool ValidateZ(int x, int y, ZValue z) {
SR.FieldInfo fi = typeof(ZValue)
.GetField(Enum.GetName(
typeof(ZValue), z));
// test all attrs (ValidForAttribute)
if(fi != null)
foreach(ValidForAttribute vfa
in fi.GetCustomAttributes(
typeof(ValidForAttribute),
true))
if (vfa.Test(x, y))
return true;
// ret false if enum not found,
// or no attrs found returning true
return false;
}

public int x, y;
public ZValue z
{
get { return _z; }
set {
if(ValidateZ(x, y, value))
_z = value;
else
throw new Exception(
string.Format(
"Invalid z: ({0}, {1}, {2})",
x, y, z));
}
}
}

then the code will validate a new value of z against x and y before setting the internal field (_z) to that value. An exception will be raised if the value is invalid. This may seem like a lot of work, instead of just validating z inside the z "set" accessor. That's true, it is. However, the real advantage to this is that the validation code can be used in other ways. For instance, consider if we wanted a list of valid values for z (for a UI, for instance) given a particular value of x and y. We can write the following code:

public static ZValue[] ValidZs(int x, int y) {
List<ZValue> zv = new List<ZValue>(
(IEnumerable<ZValue>)
Enum.GetValues(typeof(ZValue)));
zv.RemoveAll(new Predicate<ZValue>(
delegate(ZValue v)
{
SR.FieldInfo fi = typeof(ZValue)
.GetField(Enum.GetName(
typeof(ZValue),
v
));
if (fi != null)
foreach (ValidForAttribute vfa
in fi.GetCustomAttributes(
typeof(ValidForAttribute),
true))
if (vfa.Test(x, y))
return false;
return true;
}
));
}

Hope you found this interesting! Email with questions, if you have them!

Saturday, January 6, 2007

Anonymous Delegates in C#

A friend asked me recently what features other than Generics I really liked in C# 2.0. I mentioned that the anonymous delegate is one of those features. So, you might ask, what is an anonymous delegate? First of all, for those of you who don't know what delegates are, they are the C# equivalent of a function pointer, sortof.

A delegate is a strongly typed method pointer, that stores both the method reference and the object reference on which the method is defined. Delegates are declared with the syntax:

[access] delegate [return type]
[delegate name] ( [param signatures] )

where [access] is an access modifier (optional) - public, private, protected, or internal, return type is the return type of methods that will be pointed to by the delegate (or void), and the other items are relatively self-explanatory.

Now. That's how a delegate "type" is declared. However, anonymous delegates aren't really delegate types - they're delegate instances. Let's say we have a delegate called BinaryIntegerOperation declared as:

public delegate int
BinaryIntegerOperation (int a, int b);

This declaration gives us a delegate type called BinaryIntegerOperation. If we want to create a delegate instance, we need to pass the name of a function with the appropriate signature to this delegate's constructor during a invocation of the new operator. Let's assume that we have a class declared as:

public class Adder {
public int Add(int x1, int x2) {
return x1 + x2;
}
}

Let's also assume that we have some instance of the Adder class, referenced by a variable called myAdder, within the context of the code we care about. The code to construct a delegate instance of BinaryIntegerOperation using the Add method of our myAdder object instance would look like:

...
BinaryIntegerOperation op
= new BinaryIntegerOperation(
myAdder.Add);
...

and the code to invoke this delegate would look like:

int result = op(value1, value2);

(just like a normal method call).

Now, let's say that instead of declaring an Adder class, we just wanted to be able to pass some simple implementation of the BinaryIntegerOperation delegate's method signature to the delegate's constructor so that we could use it in a context that needs a BinaryIntegerOperation instance. We can do the following, instead of declaring a Adder object altogether:

BinaryIntegerOperation op
= new BinaryIntegerOperation(
delegate (int a, int b) {
return a + b;
});

As you can see from this code, the code for the delegate instance is actually placed inline using the delegate keyword, along with the parameter signatures of the method. C# will automatically create a class, instance, and method for us, so we don't have to do so ourselves.

You might say, what is the advantage of this? I use this feature very extensively, often in code dealing with list filtering or searching.

Let's say you have a list of integers, and you want to determine if any of them is larger than a particular value (say 10).

Consider the code (list is List<int>)

bool bigger = false;
foreach(int item in list) {
if(item > 10) {
bigger = true;
break;
}
}

you could instead write it as:

bool bigger =
-1 != list.FindIndex(
new Predicate<int>(
delegate (int x) {
return x > 10;
}));

where, again, list is List<int>.

Friday, January 5, 2007

The ClickOnce reference (on MSDN)

Just in case you want to learn a bit about ClickOnce yourself, from the source, you can do so on the MSDN site here: http://msdn2.microsoft.com/en-us/library/6ae39a7c(VS.80).aspx

Clickonce Deployment Tidbits

Ok... First, I'm going to talk about CD-ROM based initial installations, 'cause that's what I know best. The scenario where this install type works best is as follows:
  • Application prerequisites are quite large (SQL Server, stuff like that...)
  • Application updates should be delivered via the web
  • Application should be available offline (see the "Offline as well" option in Install Mode and Settings under Publish properties of your VS2005 project).
  • Application may have custom prerequisites (another article in itself, coming soon).

We typically configure our applications so that they don't have a deployment web page, but either way is fine (this option is in the Options... dialog). For the purposes of discussion, I'm going to assume the program name is MyApp and that the only files deployed with the application will be the app.config and the app exe.

To set up the application to publish to CD-ROM or DVD-ROM, you should choose a publish location that is a file path on your local machine. We typically use c:\deployments\... or something like that. For the purposes of discussion, I'm using c:\deploy\MyApp\v1.0.0.0 as my first deployment location. You'll want to have a version number in your deployment location so that you don't overwrite older deployments when creating new ones.

So, for version 1.0 of our application, we'll set the deployment location to c:\deploy\MyApp\v1.0.0.0. It's tempting to put something in the "Installation URL" but we won't for building the initial CDs to deploy from. It's also tempting to let visual studio automatically increment the revision with each publish. However, we prefer to have total control over the version number used for publish and for the assembly version (stored in the AssemblyInfo.cs file). There are actually a ton of different version numbers floating around in .NET applications. In our simple case here, there's the Deployment version, the Assembly version, and the Assembly file version. We like to keep all of them in sync. Things can get very confusing otherwise. I'm not going to talk much about the significance of each different version number here, unless requested to do so, so make a request if you want more details about them.

So, on to the publish. We're looking to publish our application to a CD, but also to be able to update it from the web. Let's say you have a web server available (we'll use localhost for these examples). If you create a site (or virtual directory) called MyApp on your IIS install, it will be easier to follow my examples. I'm going to use the path http://localhost/MyApp/updates as my updates deployment path. So, let's click on the Updates... button and see what we see.

In the updates dialog, we obviously want "Application should check for updates" checked, since that's the whole point of this discussion. I would choose "Before the application starts" for the when, since the other alternative is very strange. For now, leave the "minimum required version" blank. For the update location, let's put our http://localhost/MyApp/updates path.

Close the dialog and click publish now. After a few moments, you should see an explorer window pop up with the deployment files in it. Let's look at those files for a moment. There should be a setup.exe - it's the setup bootstrapper that knows how to install your prerequisites and get the ball rolling on the installation. There's also a couple of .application files. The unversioned one and the versioned one are identical (in contents).

These files can be copied to a CD-ROM or DVD-ROM and installed from there, by clicking the Setup.exe. However, we also need to set up the path for updates too. Let's talk about how to deploy the updates to a web server. Whereever you placed your virtual folder (physically) on your web server, you need to copy the .application files and the MyApp_1_0_0_0 folder to that location. In my case, http://localhost/MyApp refers to a "C:\MyApp Deployment" folder on my local hard drive. Since I want the files to be in the "./updates" path relative to this virtual folder, I need a "updates" folder in this folder. I then need to copy those files to the "updates" folder. I should make sure the permissions on those files and folders are appropriate for the users I wish to be able to access this application (normally anonymous access is needed if you want to deploy the application to anyone that wants it).

Once you've copied those files and set up those folders, you should be good to go for your first CD-based ClickOnce deployment. Run the setup.exe from the CD to install the application. If you run Setup.exe the app should install (after warning you about security) and then immediately run itself. You'll see that the app should also appear in your start menu and in the add/remove programs control panel applet.

Now, let's update the application and see a new version deployed. In my case, the original application didn't do anything and was simply a blank form (from the new application wizard). To make version 1.1, I'm going to add a label to the form with some text so I can tell I've got the new version. Once you've done that, deploy again, but to a v1.1.0.0 folder, and change the deployment version (and assembly versions in AssemblyInfo.cs) first. Do this by going to the publish properties (in the project properties) and setting the major and minor publish versions as appropriate. Now publish to the new folder. Once the publish is done, you should see the explorer window pop up. Copy the .application files and the MyApp_1_1_0_0 folder to the updates folder in your web server again. This will replace the MyApp.application that was put there for version 1.0.

Now, let's see the application update itself. Click the application from the start menu and see what happens. The application should ask you if you want to update. DON'T click SKIP! It won't ask you again for a long time if you do (I'm not sure how long). If you don't want your users to be able to skip updates, set a required version equal to your current version each time you deploy (in the Updates... dialog of the Publish settings).

Anyway, you've just done your first ClickOnce deployment. More tidbits to come.

Thursday, January 4, 2007

.NET Xml Serialization with complex collections

So, the other day, I was doing some XML serialization work in .NET and I thought to myself, I need some more complex collection members in this XML heirarchy but I'd still like them to be serialized. What do I mean? Well, the default type of collections used by the XML serialization in .NET (if you use xsd.exe to generate the code for your serialization classes) is a strongly typed array. For instance, let's say I have XML that looks like the following:

<root>
<entry id="1" value="hello">
<entry id="2" value="there">
</root>

Now, let's say I use xsd.exe to generate my code (first I run xsd to infer the schema, then I run it to generate classes for this schema). I'll get two classes - one of them will be called "root" and the other "rootEntry". The class named "root" will get a member called Items declared as

private rootEntry[] itemsField;

/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("entry",
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public rootEntry[] Items {
get {
return this.itemsField;
}
set {
this.itemsField = value;
}
}

My issue was this - I wanted to use my classes to generate XML, not just read it. In the case of generating XML using these classes, it's a bit of a pain to have to build the array first, before attaching it to the class. It'd be much nicer if I could just have a List<rootentry> as my collection type.

Well, it turns out, that having a List<rootentry> as the collection type of the Items property is quite easy! The .NET framework even knows how to construct it for you, so you don't have to construct it by default. All you need to do is change the declarations above from rootEntry[] to List<rootentry> (include System.Collections.Generic in your using list, of course).

All that is fine, but I would like to use a custom IList<rootentry> implementation so that my collection can have other niceties (like providing notifications when one of the entries has changed in value, etc.), so I want to use my own collection type. At first, I thought I could just derive from List<rootentry> to build my collection type, but unfortunely, most of the stuff in List is not virtual, so it can't be overridden. Therefore, I decided to try building a list object that implements IList<rootentry> and see what happens.

My class was declared like this:


public class OwnedList<TElem, TOwner>: IList<TElem> {
private List<TElem> _Items;
private TOwner _Owner;

public OwnedList(TOwner Owner)
{
this._Items = new List<TElem>();
this._Owner = Owner;
}

...
}

Then, I used it in the property and field for root like:


private OwnedList<rootEntry, root> itemsField;

// constructor added so that itemsField is not
// NULL anymore when the serializer or caller
// gets the object.
public root() {
this.itemsField
= new OwnedList<rootEntry, root>(this);
}

/// <remarks>
[System.Xml.Serialization.XmlElementAttribute("entry",
Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public OwnedList<rootEntry, root> Items {
get {
return this.itemsField;
}
}

Notice, I removed the "set" accessor for the property and added a constructor for root that creates the collection. This is necessary so that my collection gets the appropriate "Owner" when it is created. Now, I can write code to use normal IList operations on my Items collection when building my list of items, rather than having to build the array before adding it to the object. Xml serialization works and gives the identical results to before!

Happy coding!