I love Reflector. It has been invaluable in my various continuous learning efforts, poking around interesting code to improve my own. However, the need for Reflector spans beyond curiosity: when working with the SharePoint object model, it is an essential tool to understand what’s going on behind the scenes. It would be great if the API always did what you expect, or at least documented some of its less-than-obvious behavior, but it doesn’t and probably never will. It’s simply too big and “what you expect” is often a matter of opinion.
An excellent example is the behavior of SPList.DefaultView
. As recently discovered by Andy Burns and earlier documented by , DefaultView
returns a new SPView
instance on every call. So instead of this:
list.DefaultView.ViewFields.Add("SomeField");
list.DefaultView.Update();
You need to do this:
SPView defView = list.DefaultView;
defView.ViewFields.Add("SomeField");
defView.Update();
Daniel was able to verify this behavior with the VS debugger, but it’s not clear why. Enter Reflector:
- SPList.DefaultView:
public SPView DefaultView
{
get
{
return this.Views.DefaultView;
}
}
- SPViewCollection.DefaultView:
internal SPView DefaultView
{
get
{
if (this.m_iDefaultViewIndex != -1)
{
return this[this.m_iDefaultViewIndex];
}
return null;
}
}
- SPViewCollection.Item[Int32]
public SPView this[int iIndex]
{
get
{
if ((iIndex < 0) || (iIndex >= this.Count))
{
throw new ArgumentOutOfRangeException();
}
return new SPView(this, this.m_arrViewSchema, iIndex);
}
}
In three clicks we see exactly what the problem was and why. Since I usually have Reflector open, this is almost always faster than asking Google or MSDN. Of course some methods are obfuscated (code can’t be disassembled), but fortunately these are exceptions rather than the rule.
Exploring SPView.ViewFields
As another example of code not behaving as expected, consider the implementation of SPView.ViewFields
:
public SPViewFieldCollection get_ViewFields()
{
if (this.m_xdView != null)
{
while (this.m_bFullBlownXmlDoc)
{
return new SPViewFieldCollection(this, this.Node);
}
}
return new SPViewFieldCollection(this, this.GetInnerXmlForNode("ViewFields"));
}
Given that a new collection is created each time, one might expect the following to add only the second field:
SPView defView = list.DefaultView;
defView.ViewFields.Add("FirstField");
defView.ViewFields.Add("SecondField");
defView.Update();
But, much to my surprise, both fields are added! So what’s going on here? Well, let’s explore a bit with PowerShell:
PS 1> $w = spw http://localhost
PS 2> $l = $w.Lists['Test']
PS 3> $dv = $l.DefaultView
PS 4> $vf1 = $dv.ViewFields
PS 5> $vf2 = $dv.ViewFields
PS 6> $vf1
Attachments
LinkTitle
PS 7> $vf1.Add('Editor')
PS 8> $vf2
Attachments
LinkTitle
Editor
So we store two different SPViewFieldCollection
objects, update one, and the other is updated as well. In my mind, this begs two questions:
- Why doesn’t SPView just store a reference to a shared collection?
- How are the collections kept in sync?
It’s tough to guess why, but Reflector can probably help us figure out how. Let’s start with one of the constructors called by ViewFields
:
internal SPViewFieldCollection(SPView view, string innerXml)
{
this.m_View = view;
this.m_ViewStyle = null;
this.m_strInnerXml = innerXml;
}
Not much to see here, other than the captured reference to the parent SPView
. Using Reflector’s Analyze function (Ctrl-R), we see that m_strInnerXml
is also referenced in the SchemaXml
property:

Which disassembles as…
public string get_SchemaXml()
{
if (this.m_node == null)
{
return this.m_strInnerXml;
}
return this.m_node.InnerXml;
}
So the value passed in is only used if m_node
has not been set. Ctrl-R again:

Now we’re getting somewhere. The members rely on EnsureViewFields()
to keep up-to-date:
private void EnsureViewFields()
{
if (this.m_node != null)
{
this.m_iCount = this.m_node.ChildNodes.Count;
}
else
{
this.m_View.EnsureFullBlownXmlDocument();
this.InitViewFields(this.m_View.Node);
}
}
And the node connection is set up in InitViewFields
using its view’s Node
. So SPViewFieldCollection
doesn’t even have an internal data store! Instead, everything operates against m_node
, which is attached to the parent view. Thus changes to one collection are immediately reflected in other collections created from the same SPView
.
I still prefer to capture and reuse the SPViewFieldCollection
, but at least now we know that it’s safe not to and, more interestingly, why that’s the case.
Time to share! When has Reflector saved you from SharePoint headaches?