// Throws System.OverflowException if // ServiceName.GetHashCode() is large enough. public override int GetHashCode() { return ServiceName.GetHashCode() + DbId; } // Explicitly decide to let the overflow wrap public override int GetHashCode() { unchecked { return ServiceName.GetHashCode() + DbId; } } // Shorter way to explicitly let the overflow wrap public override int GetHashCode() { return unchecked(ServiceName.GetHashCode() + DbId); }
Pop quiz #1
What could be wrong with this class? Think carefully and post your answer in the comments.
class Something { public string ServiceName { get; private set; } public int DbId { get; private set; } public Something(string serviceName, int dbId) { if (serviceName == null) throw new ArgumentNullException("serviceName"); ServiceName = serviceName; DbId = dbId; } public override int GetHashCode() { return ServiceName.GetHashCode() + DbId; } public override bool Equals(object obj) { Something other = obj as Something; return other != null && DbId == other.DbId && ServiceName == other.ServiceName; } }
Is it faster to cast or call ToString()?
I was wondering if I already knew an object was a string if it was faster to cast it or to call ToString(). I thought it would be faster to call ToString() because casting has to do some type checking while the String class overrides ToString to return itself:
public class String { //... public override string ToString() { return this; } }
By this reasoning, I figured that (a is string && a.ToString().Length < 4000) would be cheaper than (a is string && ((string)a).Length < 4000).
It turns out they are both six IL instructions:
Calling ToString
L_0007: ldloc.0 L_0008: isinst string L_000d: brfalse.s L_0023 L_000f: ldloc.0 L_0010: callvirt instance string [mscorlib]System.Object::ToString() L_0015: callvirt instance int32 [mscorlib]System.String::get_Length()
Casting
L_0025: ldloc.0 L_0026: isinst string L_002b: brfalse.s L_0041 L_002d: ldloc.0 L_002e: castclass string L_0033: callvirt instance int32 [mscorlib]System.String::get_Length()
So… now what is the cost difference between the castclass operator and the virtual method call to the ToString method?
Turns out the cast takes about 75% of the time of a ToString call.
using System; static class Program { static void Main() { object o = "a string"; string a; string b; Boolean r = (o is string && o.ToString().Length < 4000); r = (o is string && ((string)o).Length < 4000); DateTime t = DateTime.Now; for (int i = int.MinValue; i < int.MaxValue; i++) a = (string)o; Console.WriteLine(DateTime.Now - t); t = DateTime.Now; for (int i = int.MinValue; i < int.MaxValue; i++) b = o.ToString(); Console.WriteLine(DateTime.Now - t); } }
Using ReSharper to edit C# XML Documentation Comments
- Navigate to ReSharper | Options | Templates | Surround With.
- Expand User Templates.
- Click the Create Template toolbar button.
- Fill in a name.
- Choose where it will be Available by clicking the hyperlink. For these XML code documentation comments, I choose Language-specific for C# and check Everywhere (everywhere because none of the other options seemed to work for the comments.)
- Edit the template text to wrap $SELECTION$ with the text you want.
- Choose OK.
- If you like, you may now choose a position for your new template in the quick access list to choose which letter it can be accessed by.
Here are some of the Surround With templates I’ve set up for editing documentation comments:
Name | Template Text |
<para>
|
<para>$SELECTION$</para>
|
<see>
|
<see cref=”$SELECTION$”/>
|
<see> label
|
<see cref=”$SELECTION$”>$SELECTION$</see>
|
<note> | <note type=”caution”>$SELECTION$</note> |
- Navigate to ReSharper | Options | Templates | Live Templates.
- Expand User Templates.
- Click the Create Template toolbar button.
- Fill in an abbreviation and description. (I usually set the description to the same thing as the template text since these are usually small.)
- Choose where it will be Available by clicking the hyperlink. For these XML code documentation comments, I choose Language-specific for C# and check Everywhere (everywhere because none of the other options seemed to work for the comments.)
- Edit the template text you want to insert.
- Choose OK.
Here are some of the Live templates I’ve set up for editing documentation comments:
Abbreviation | Template Text |
seet
|
<see langword=”true”/>
|
seef
|
<see langword=”false”/>
|
seen
|
<see langword=”null”/>
|
A Hazard of Reimplementing an Explicit Interface
When implementing an interface explicitly, it is best to create virtual methods or properties if you ever expect a subclass to need to change the behavior. Implementing the interface explicitly helps to not pollute the public members of a type, but subclasses cannot reach the superclass’s implementation if they have to reimplement the interface to change the behavior. Exposing protected methods for the explicitly implemented members would keep the public interface clean while still allowing access by subclasses.
Somewhere I read a post from one of the .NET Framework developers that confirmed the superclass’s implementation would be unreachable in situations such as the one below. You can find more on Google: http://groups.google.com/groups/search?hl=en&q=explicit+interface+base+c%23
// Reimplementation of explicit interface implementation makes // superclass implementation inaccessable from subclass. internal class Program { private static void Main() { I i = new B(); System.Console.WriteLine(i.Stuff()); i = new C(); System.Console.WriteLine(i.Stuff()); } } internal interface I { int Stuff(); } internal class A : I { protected int count = 0; int I.Stuff() { return 1; } } /// <summary> /// Normal code can't get there. /// </summary> internal class B : A, I { int I.Stuff() { count++; if (count > 100) { System.Console.WriteLine("Infinite loop"); return -1; } // Doesn't compile, not allowed to use "base" here. // return 2 + ((I)base).Stuff(); return 2 + ((I) ((A) this)).Stuff(); } } /// <summary> /// Even Reflection can't get there. /// </summary> internal class C : A, I { int I.Stuff() { count++; if (count > 100) { System.Console.WriteLine("Infinite loop"); return -1; } System.Reflection.MethodInfo stuffMethodOfI; stuffMethodOfI = typeof (A).GetInterface("I").GetMethod("Stuff"); return 2 + (int) stuffMethodOfI.Invoke((A) this, null); } }
Output:
Infinite loop 199 Infinite loop 199
DataView RowFilter Performance
DataView slowWay = new DataView(table); slowWay.RowFilter = rowFilter; DataView fastWay = new DataView(table, rowFilter, String.Empty, DataViewRowState.CurrentRows);
Create Less Garbage with EventArgs.Empty
Event Properties
Don’t forget about event properties.
Sometimes an interface requires an event that really is the same as an existing event. This can be accomplished by forwarding the new to the existing event.
There is nothing wrong with this version:
public event EventHandler ValueChanged; protected override void OnCheckedValueChanged() { base.OnCheckedValueChanged(); EventHandler handler = ValueChanged; if handler != null) { handler(this, EventArgs.Empty); } }
This does the same thing and I think this version is cleaner:
public event EventHandler ValueChanged { add { CheckedChanged += value; } remove { CheckedChanged -= value; } }