December 2005 - Posts
You can download them hereDrew Robbins, Josh Holmes and gave the developer care presentation on Visual Studio Team System. You can get the slides, and presentations at the link below.
The slides and demosAre available here
Why I still don't think it's that useful.I received the following comment from a reader last week, and I thought the answer could generate some discussion here:
Hi Bill,
I’m currently reading your book and am thoroughly enjoying it. I’m an experienced C++ developer but have only been working with C# a couple of months. Therefore I really appreciate all the great advice. However I would like some clarification on item 27.
I agree completely that ICloneable is not necessary for value types. With regard to reference types, I have interpreted ICloneable as a standard way of implementing a ‘virtual copy constructor’. In my opinion the main benefit of this pattern is for code to work purely with a base type reference and still have the ability to create a copy of any type derived from the base type.
Therefore I believe that Base classes should implement ICloneable when required. A more realistic code example would be as follows.
static void Main(string[] args)
{
BaseType b = new Derived();
BaseType b2 = b.Clone();
Debug.Assert(b2 is Derived);
}
I believe that with regard to reference types, implementing ICloneable indicates that the reference type supports a ‘virtual copy constructor’ and shallow or deep copying.
If shallow or deep copying is required of a reference type that is not intended to be part of a class hierarchy, then the class should be marked as sealed and a public copy constructor exposed.
Here’s my answer:
You example below does describe exactly how we’d all like ICloneable to work. In almost all cases, b2 would have the runtime type of BaseType. Because that’s surprising, and not the behavior you would desire, I tend to avoid ICloneable in most cases. Item 20 explains why implementing ICloneable in base classes will often lead to slicing the object in derived classes.
Your best option to implement ICloneable in a base class, and still create copies of derived classes is to follow the idiom used for IDisposable in Item 18. Have the base class implement ICloneable, and its implementation could call a virtual CreateCopy() method. Something like this:
public class BaseType : ICloneable
{
protected BaseType( BaseType src )
{
// elided
}
public object Clone()
{
return CreateCopy( this );
}
protected virtual object CreateCopy( BaseType src )
{
return new BaseType ( src );
}
}
public class Derived : BaseType
{
protected Derived ( Derived src ) :
BaseType( src )
{
// elided
}
protected override object CreateCopy( BaseType src )
{
Derived d = src as Derived;
return new Derived( d );
}
}
Notice that even with this solution, the not-so-clever developer can get into trouble:
. If a derived class author does not implement CreateCopy correctly, slicing still occurs.
. If the derived class does not construct a copy using the copy constructor in the base class, a form of reverse slicing occurs (the base class portion of the object would have default values, rather than a copy).
Given all these problems, ICloneable is just not as useful in practice as it appears.
I’d like your comments as well. What do you think?
Now it's rolling through my headIf this isn't enough to bring back the 'Avalon' name, I don't know what will be. Charles Petzold has penned lyrics based on a Devo song to celebrate WPF
excerpt:
"When a project comes along
You must Whippif"
Please make it stop
Charle's original postWhippif good
making it more efficient to drill into specific fields.OK, I probably should have realized this earlier, but I’ve probably been spending too much time using VS2005 and too little using VS2003 lately.
Often, the default display for the VS debugger is not the best format to display your own types. In VS2005, you have visualizers (more on that later), but in VS2005, the best you can do is modify the mcee_cs.dat file (or mcee_mc.dat if you’re using Managed C++).
This nifty little file lives in “C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Packates\Debugger”.
This file describes how the debugger automatically expands different types in your application. For example, this designation:
<System.Collections.ArrayList>=Count=<Count>
Describes how the debugger should format any ArrayList you use. You can specify more than one item:
<System.Windows.Forms.SplitterEventArgs>=SplitX=<splitX> SplitY=<splitY>
I certainly don’t add every type I create, but for some core types in a big project, it can be a big help.
The extra syntax in Java just don't seem that useful to me.There’s been an interesting discussion on the Visual C# language forums relating to generic class constraints. For background, C# lets you specify two forms of constraints in a generic class. First, you can specify that the generic type must be derived from a particular base class:
public class MyType<T> where T : MyBaseClass
means that any class you substitute for T must be derived from MyBaseClass.
Secondly, you can specify that T must implement some interface:
public class MyType<T> where T : IComparable
As a special case, you can also specify a generic interface:
public class MyType<T> where T : IComparable<T>
What you can’t do in C# (but you can in Java) is specify that the type substituted for a generic parameter is a base class of some type
// In Java 5:
void setComparer( Comparator<? super E> c ) { … }
I may be in the minority here, but I just don’t see compelling needs for that additional language functionality. I’m not going to post the original example, but if you go here: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=104825&SiteID=1 you can see the entire thread.
The book example from the above link is interesting, but I can easily provide two possible modifications within the C# language that work just as well, or even better.
The first plan is to modify the NamedObjectComparer class so that it’s a generic class, and simply use that:
public class NamedObjectComparer<T> : IComparer<T>
where T : INamedObject
{ … }
Then, you create the sorted collection using this class:
new SortedCollection<Book>(new NamedObjectComparer<Book>());
In my opinion, this has a couple advantages over the version posted. First, I’m concerned about the non-generic NamedObjectComparer:
public class NamedObjectComparer: IComparer<INamedObject>
{
public int Compare(INamedObject a, INamedObject b)
{
return String.Compare(a.Name, b.Name);
}
}
I’m not sure this has real meaning (or at least that it’s really what the author intended). The NamedObjectComparer can be used to compare any two objects that have names. Do you really want to compare a Book to an Employee? Or a Street to a Customer? That’s valid with this object, but I doubt that have a proper semantic meaning.
Of course, if you really did intend to compare different types that both have names, simply change the declaration of the collection:
new SortedCollection<INamedObject>(new NamedObjectComparer());
But, based on the examples in the forum, I can’t find a reasonable use case for constraining a type to be a superclass of a type rather than a subtype. If you have a good example, I’m interested in seeing it. Please comment or respond in the original forum.
Thanks to Jim HolmesJim Holmes has been writing a series of articles for James Avery at visualstudiohacks.com. The latest is on debugging techniques. In addition to me, SRT Solutions' own Josh Holmes is quoted as well.
It's a good article featuring tips from James Avery, Kate Gregory, Scott Hanselman, Drew Robbins, and many others.
Check it out.