More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  DevelopmentalProfileFriendsBlogMore Tools Explore the Spaces community

Developmental

Flinging crap at other monkeys in the development forest
July 01

Rolling back a changeset in TFS

In TFS 2005 and 2008 there is no easy way of rolling back a changeset. Sure, you can do a "get specific version" of each file from before the "bad" checkin occurred, and then check the older version back in. But this really sucks if you have a lot of files in your changeset.

Luckily the Team Foundation Power Tools can help you here. One of the command line options is as follows:

tfpt rollback /changeset:xxxx

Here, you simply replace xxxx with your changeset number, and the power tools will take care of the rest.

First, it will "get latest" of the workspace. Next it will perform an operation for each file that is required to roll it back. For example, if you added a file, it performs a delete. If you deleted a file, it performs an undelete. If you simply edited a file, it will get the code from the changeset previous for that file. The result on the command line indicates which changeset was used for each file it rolled back.

It then pops up a window requesting confirmation for all the files. After this, it checks out all those files it will roll back and you can then check them in (or only check some in if you so wish).

One caveat with this process is that when you are executing the command line, you might get an error: "Unable to determine workspace". This simply means you are not currently in a folder that is part of a workspace. Change directory into a folder that is stored in the workspace you want to use (for those that use multiple workspaces with different folders).

Good news is that Rosario will have rollback features incorporated. Check out the help for rollback for more information:

tfpt rollback /?

Technorati Tags: ,,,,
June 13

Destroy Work Item : Is it really gone?

This week we had a situation where we needed to remove a work item from the TFS database completely. You can delete a work item in Team Explorer however this just marks the row in the database as deleted and as such your database will always grow, never shrink.

The Visual Studio Team System 2008 Team Foundation Power Tools give us the ability to destroy a work item with the 'destroyWI' call. Here's the command line syntax:

tfpt destroywi /server:<SERVER> /workitemid:<ID>

The 'intention' is to delete all instances of the ID from the database, and all related data, and in truth it comes pretty close. However there is one table it misses: 'WorkItemsWere'

If you look at your TFS database instance you will notice there are actually a few databases. One of them is 'WorkItemTracking' and this database contains all the tables related to work items. The astute might also notice that each of the databases in their instance seems to match each of the web services provided by TFS. Coincidence?

In the 'WorkItemTracking' database you will see a number of tables that all contain work item related data. In particular, notice the two tables: 'WorkItemsAre' and 'WorkItemsWere'. The 'Are' table contains the current state of a work item while the 'Were' table contains its history.

For example, work item 1234 is modified several times. First it is opened as a bug and assigned to 'triage'. Then triage moves it to the developer who fixes the bug and resolves it with comments, where it is assigned back to the user who opened it. The bug isn't fixed, some additional comments are inserted, its assigned back to the developer, and so on. If you are familiar with work items, you will be able to identify the 'History' section where you can view the audit history. This essentially is what is stored in the 'WorkItemsWere' table. Makes sense now right?

Yesterday I did a destroy of a work item and discovered that all the various tables had all instances cleaned up, except the 'WorkItemsWere' table. I contacted the VSTS team who indicated that this is indeed a bug and it is now logged in their own work item system (oh the irony!).

What to do in the mean time? Well they assure me it is safe to delete the orphaned database rows, despite the general consensus on the net not to mess with the database directly. I can confirm however that this is the only table with orphaned data. And I'm sure this will be fixed up in a future release of the power tools. All round I quite like the TFPT and haven't even bothered with the multitude of 3rd party components that put a UI in front of it: real men use command line!

June 01

Advanced Generics

I've recently been reading this book by Jon Skeet about C# 2 and 3, and it got me all inspired to write about generics. Jon's great; he's extremely active in the C# and Java community, and recently responded to an email question I had in less than 10 minutes! I'm finding the book insightful and useful and greatly enjoying my bus rides to work when I get to read it.

This post is going to assume you are familiar with using generic classes like List<T> and Nullable<T>. So lets start with the syntax for declaring our own generic class:

public class Monkey { }
public class Animator<T> {
    private T instance;
    public Animator(T t)
    {
        instance = t;
    }
    public void MoveOnce() { }
}
Animator<Monkey> animator = new Animator<Monkey>(new Monkey());
animator.Move();

This is pretty simple: the Animator class accepts a generic type T and requires you pass a T in its constructor. The MoveOnce() method is empty at the moment, we'll get to that later.

Currently our generic Animator class is somewhat type-safe: we can only pass instances of T to its constructor, but we don't really know much about T. We'd like to be able to move our instances (such as a monkey) so we need to define some things about what kinds of T we are willing to accept. Lets go back to our Monkey class for a moment and define an interface for it:

public interface IMoveable {
    void Move();
    void Stop();
}
public class Monkey : IMoveable {
    public void Move() { }
    public void Stop() { }
}

Great! We've decided that the fact a Monkey can move and stop is pretty general, and is probably something other animals can do, so we've declared an interface to indicate our monkey has those capabilities. We might also define IEater, or IDungFlinger. Now we can revisit our generic type in our Animator class definition as follows:

public class Animator<T> where T : IMoveable
{
    private T instance;
    public Animator(T t)
    {
        instance = t;
    }
    public void MoveOnce() {
        instance.Move();
        instance.Stop();
    }
}

This is where the magic begins. We've placed a constraint on our generic type, stating that it will only ever accept a type that implements our IMoveable interface. If we try to use the Animator class with something else, we will get a compile-time exception. Even better yet is that our development environment knows that since our instance will always implement IMoveable, it therefore must have a Move() and Stop() method, therefore we can call it anywhere in our class; in this case the MoveOnce() method.

You can declare more than one generic type in your class definitions. Imaging a class that facilitates a race for monkeys, whether they be chimps, gorillas, or marmosets. Consider this generic class declaration:

public class Race<T, U> where T : Monkey where U : Monkey {
    public Race(T monkey1, U monkey2) { }
    public void RunRace() { }
}
public class Marmoset : Monkey { }
public class Chimp : Monkey { }

Here we have defined that our class accepts 2 generic types: T and U. We have further restricted them that they both have to inherit from the Monkey class. Here's some example calls using this new class:

Race<Chimp, Marmoset> race1 =
      new Race<Chimp, Marmoset>(new Chimp(), new Marmoset());
Race<Monkey, Chimp> race2 =
      new Race<Monkey, Chimp>(new Monkey(), new Chimp());
Race<Marmoset, Marmoset> race3 =
      new Race<Marmoset, Marmoset>(new Marmoset(), new Marmoset());

As you can see that anything that inherits Monkey is valid. Of interest, the second example shows that even an instance of Monkey is valid. This shows that the where clause in our type restriction means anything that inherits from X or is X.

Finally here are a couple of extra cool things you can do with generic type restrictions as general non-monkey related examples:

public class TestCase1<T> where T : class { }
public class TestCase2<T> where T : struct { }
public class TestCase3<T> where T : IDisposable, IMoveable, IComparable { }
public class TestCase4<T, U> where T : U { }
public class TestCase5<T, U> where T : U, IMoveable { }
public class TestCase6<T, U> where T : class where U : struct{ }
public class TestCase7<T, U> where T : class where U : struct, T { }

TestCase1 demonstrates that we can force the type to be a reference type.
Likewise TestCase2 ensures that the type must be a value type. How is this useful? Well consider a generic class that performs expensive operations such as copying from one list to another. Reference types are just pointers and therefore inexpensive to copy around, thus ensuring only reference types are allowed in our class could be quite useful.

TestCase3 shows that we can ensure T implements multiple interfaces.
TestCase4 shows that one generic type can be forced to inherit from another. An example of an implementation might be:

TestCase4<Chimp, Monkey> test = new TestCase4<Chimp, Monkey>();

This is valid because Chimp inherits from Monkey.
TestCase5 shows that a type can be restricted to inherit as well as implement interfaces.
TestCase6 demonstrates that one type must be a reference type while the other can be a value type.

The last TestCase7 is somewhat interesting. Its declaration indicates that T is a reference type, and U is a value type that must inherit from T. How can this be? It essentially states that you must pass a struct that inherits from a class. But C# won't let you declare this.

To be honest at first I didn't know the answer to this. Thus the email to Jon, and his explanation was simple and it made sense: interfaces are reference types. Hopefully you are aware that structs can implement interfaces also (but can't do inheritance), so we might define a new animal as follows:

public struct Mouse : IMoveable {
    public void Move() { }
    public void Stop() { }
}

Then we can legitimately use the TestCase7 syntax:

TestCase7<IMoveable, Mouse> test = new TestCase7<IMoveable, Mouse>();

Then of course, valid values for an IMoveable are a Chimp, Marmoset, or even another Mouse, while of course you can only use a Mouse for the second type.

Hopefully this has given you a better idea of what you can do with generics.

May 29

Contravariance, Covariance, and Generics

The common question is: what the hell is contravariance and covariance?

Ok so you are familiar with casting right? In C# we can do this:

public class Animal { }
public class Monkey : Animal { }
...
Animal a = new Monkey();
((Monkey)a).FlingCrap();

We can also do this:

public void MoveWest(Animal a) { }
...
MoveWest(new Monkey());

Because the 'MoveWest' method accepts the narrowing type 'Animal' it is said to support 'Contravariance'. If the C# compiler forced us to only pass exact types, then it would be considered 'invariant'. Likewise C# methods support covariance, in that we can return a narrower type and cast the resulting instance to its correct form.

There are parts of the .Net framework however that aren't so flexible. In this case, I'm talking about generics.

Consider this for example:
List<Monkey> monkeys = new List<Monkey>();
monkeys .Add(new Monkey());
List<Animal> animals = monkeys;

Unfortunately this does not compile. We get the following warning:

Cannot implicitly convert type 'System.Collections.Generic.List<FeaturesCsharp2.Monkey>' to 'System.Collections.Generic.List<FeaturesCsharp2.Animal>'

Why is this? Monkey inherits Animal, so the list conversion is perfectly safe. Well this is one case of invariance. But here's the kicker: word on the street is that the CLR actually supports contravariance of generic lists; its just the C# compiler that doesn't!

Circle Of Interest

My mate and fellow Readifarian Paul Stovell recently posted his 'Circle Of Interest' and started a meme by nominating 5 others to do the same. I was one of the lucky ones, so here's my circle.

Corethings

I don't doubt this circle will change completely in 6 months. I expect the TFS parts to fade into the middle circle, with more focus on WPF and SilverLight perhaps. Who can tell?

The big red circle indicates things I don't care about, the baby-vomit yellow indicates stuff I am interest in but have little time or dedication to fully pursue. The dog-vomit green is the stuff that I am loving working or am most eager to develop as soon as possible.

Oh, WCF shouldn't be in the middle circle, but I couldn't be bothered changing it.

Now, to continue the meme, I nominate these people:

Matthew Rowan , John McFadyen , Joseph Cooney , Leon Bambrick

Get to it chumps!

View more entries