C# coding standards document

A colleague of mine directed me to this C# coding standards document.(PDF document) on idesign.net.

It's pretty good.  I'd say I agreed with about 99% of the things in there.  One to be wary of is the author's desire to make every member virtual, which is bad for perf, and also doesn't make common sense to me with regards to having a “locked down” class that you open up more over time.

3 Comments

  • I definitely agree with not making everything virtual, however I don't see it as being that much of a performance hit. Write a class, then write another class that uses the first one. Notice that even on non-virtual methods the callvirt IL instruction is used. I assume that the compiler makes the assumption that the class could change, so users of the class should only explicitly virtually call methods on the class, whereas if you call the same methods from WITHIN your class, the IL instruction varies appropriately between call and callvirt.



    public class Class1

    {

    public Class1()

    {

    DoSomething();

    DoSomethingElse();

    }



    public virtual void DoSomething()

    {

    }



    public void DoSomethingElse()

    {

    }

    }



    public class Class2 : Class1

    {

    public Class2()

    {

    DoSomething();

    DoSomethingElse();

    base.DoSomething();

    base.DoSomethingElse();

    }

    public override void DoSomething() {}

    }



    public sealed class Class3 : Class1

    {

    public Class3()

    {

    DoSomething();

    DoSomethingElse();

    base.DoSomething();

    base.DoSomethingElse();

    }

    }







    public class Class4

    {

    public Class4()

    {

    Class1 c1 = new Class1();

    Class2 c2 = new Class2();

    Class3 c3 = new Class3();



    c1.DoSomething();

    c1.DoSomethingElse();

    c2.DoSomething();

    c2.DoSomethingElse();

    c3.DoSomething();

    c3.DoSomethingElse();

    }

    }

  • Oh and by the way, in Class4, the IL looks like so:



    IL_0000: ldarg.0

    IL_0001: call instance void [mscorlib]System.Object::.ctor()

    IL_0006: newobj instance void CallVirtTest.Class1::.ctor()

    IL_000b: stloc.0

    IL_000c: newobj instance void CallVirtTest.Class2::.ctor()

    IL_0011: stloc.1

    IL_0012: newobj instance void CallVirtTest.Class3::.ctor()

    IL_0017: stloc.2

    IL_0018: ldloc.0

    IL_0019: callvirt instance void CallVirtTest.Class1::DoSomething()

    IL_001e: ldloc.0

    IL_001f: callvirt instance void CallVirtTest.Class1::DoSomethingElse()

    IL_0024: ldloc.1

    IL_0025: callvirt instance void CallVirtTest.Class1::DoSomething()

    IL_002a: ldloc.1

    IL_002b: callvirt instance void CallVirtTest.Class1::DoSomethingElse()

    IL_0030: ldloc.2

    IL_0031: callvirt instance void CallVirtTest.Class1::DoSomething()

    IL_0036: ldloc.2

    IL_0037: callvirt instance void CallVirtTest.Class1::DoSomethingElse()

    IL_003c: ret

  • I completely agree with using default case in switch, but why you should use System.Diagnostics.Debug class in #50?



    switch(number)

    {

    ...

    default:

    Debug.Assert(false);

    }

    What if default case occured in realease? What about Trace.Assert(), by default it works in both debug and release builds?

Comments have been disabled for this content.