October 2008 Entries
SPList.Update() doesn't update an SPList

Well it does, but when it feels like it, not straight away.

I have two event handlers in a list called 'Tasks'. The first event handler is on ItemAdding, the second on ItemAdded.

In ItemAdding I add a column to a separate list called 'Attributes'. In ItemAdded I reference this new column. I receive and exception because the new column in the Attributes list does not exists, yet.

I changed the code in ItemAdding so the next line after adding the column I call attributesList.Update() for force/commit the change to the Attributes list. However, this method does not do what it appears to.

SPList.Update() did not update the attribute list. After ItemUpdating had completed and we are into ItemUpdated there is still no new column. The column only gets created sometime after ItemUpdated has finished, or whenever SharePoint can get round to it.

Annoyingly when you reflect on SPList.Update it is obfuscated, so who knows what this method does? The only info on msdn states "Updates the database with changes that are made to the list.". Sure.

I learnt two things here:

  1. There is no way in SharePoint to force a commit now
  2. You cannot rely on things being done between ItemUpdating and ItemUpdated
Suppress compiler warnings from your code

You can hide compiler warnings by adding some key words to your class.

Ok, there are very few situations when you would want to do this. Some argue that it should never be done and no code should have warnings. However, if you are really sure then you can use the following.

In my example I have a class that overrides the Equals method but not the GetHashCode method. There is no way of returning a correct hash code in this situation and overriding it and calling the base would suggest the class takes responsibility for that being correct.

So the compiler throws up this warning:

warning CS0659: SPListItemChange' overrides Object.Equals(object o) but does not override Object.GetHashCode()

Fair enough.

In my class definition I can add the following:

#pragma warning disable 0659 //override Equals but not GetHashCode
public class SPListItemChange

{

A short compile later 0 warnings.

ICloneable

Recently I wanted to create a class that had the ability to clone itself. Here is a simple example class:

internal class CloneableObject
{
     private string message;

     internal CloneableObject(string message)
     {
         this.message = message;
     } 
}

upon implementing the ICloneable interface I noticed the interface specified the return type of object.

#region ICloneable Members

public object Clone()
{
     return new CloneableObject("A am a IClonable object");
}

#endregion

My initial opinion was that this wasn't that helpful. You are only ever going to want a CloneableObject returned from CloneableObject.Clone() and I would prefer to avoid casting for runtime type safety and performance.

I can appreciate why IClonable is like this, its not like you can implement your interface in a generic way, e.g.

public interface ICloneable
{
    <T> Clone();
}

So, I implemented both ways. One way for those consumers that know it is a ClonableObject and the other way for those who just care that its IClonable.

internal class CloneableObject : ICloneable
{
    private string message;

    internal string Message { get { return message; } }

    internal CloneableObject(string message)
    {
        this.message = message;
    }

    internal CloneableObject Clone()
    {
        return new CloneableObject("I am a CloneableObject");
    }

    #region ICloneable Members

    object ICloneable.Clone()
    {
        return new CloneableObject("I am ICloneable");
    }

    #endregion
}

At this point I should point out that I know it should be return new CloneableObject(this.message) as it should be creating a copy of the original not just making up the members, but for this example, it suits.

My next question was, which Clone() gets called when?

The obvious answer is object ICloneable.Clone() when the consumer treats it as a ICloneable object and CloneableObject Clone() when treated as a Cloneable object.

static void Main(string[] args)
        {
            CloneableObject first = new CloneableObject("original");
            ICloneable second = new CloneableObject("original");

            Console.WriteLine(first.Clone());
            Console.WriteLine(second.Clone());
            Console.ReadLine();
        }

image

Best of both worlds in my opinion. I guess the question to ask is why are you implementing ICloneable? Do you consumer classes care?