You asked for it, you got it.. feedback always welcome.

 

 

 

Attribute Usage

         Suffix with “Attribute”

         Perf tip: seal attribute classes for faster runtime lookup

         Specify the AttributeUsage attribute completely

         Don’t rely on the defaults!

         Be as restrictive as possible

         You can always open it up later

[AttributeUsage(
      AttributeTargets.All,
      Inherited = true,
      AllowMultiple = false)]

 

         AttributeTargets – where is the attribute allowed to be applied?

         Inherited – should derived members/types be considered to have this attribute?

         AllowMultiple – Is it legal to put more than one instance of the attribute on a particular member?

 

         Use constructor arguments for required parameters (positional arguments)

         Provide a read-only property with the same name

         Use read-write properties for optional parameters (named arguments)

         Never use overloaded constructors

[AttributeUsage(AttributeTargets.All, AllowMultiple=true,
                   Inherited=false)]
public class NameAttribute : Attribute {
   public NameAttribute (string userName) {..}
   public string UserName {get {..}}
   public int Age {get {..} set{..}}
} //end class

 

Usage:

[NameAttribute("Bob", Age=87)]

 

UserName – positional argument

Age – named argument

 

Static Classes

         Static classes contain just static members

         Compromise between pure OO design with usability

         Commonly used for

         Shortcuts for other operations (System.IO.File)

         Functionality for which a full OO wrapper is unwarranted (System.Environment)

 

public sealed class Environment  {

  private Environment(){} //prevents creation

  public static void Exit(int exitCode) {..}

  public static int ExitCode {

    get {..}

    set {..}

  }

  public static string CommandLine {

    get {..}

  }

}

 

         Best used when:

         Clear charter for the class

         Not a “miscellaneous” bucket

         Not the center point of a design

         Use sparingly

         Watch out for disconnected design

         Static classes

         Are sealed

         Have private default constructor

         No instance members

         Static Classes: Bad Design

         Late in the final milestone we added a method to tell if the runtime is being shut down

         However we added the method as an instance method making it completely uncallable

         public sealed class Environment {
   private Environment() {} //Prevent creation
   // ---snip---
   public bool HasShutdownStarted {
      get { return nativeHasShutdown(); }
   }
   public static string UserName { get {...} }
   private static extern bool nativeHasShutdown();
   // ---snip---
}

          

 

Constructors

         Do minimal work in the constructor

         Only capture the parameters

         Cost is delayed

         You can throw exceptions from constructors

         Be consistent in the ordering and naming of constructor parameters

 

public class Foo  {
   private const string defaultA = "..";
   private const string defaultB = "..";
   public Foo():
      this(defaultA,defaultB) {}
   public Foo(string a):
      this(a, defaultB) {}
   public Foo(string a, string b) {
       /* do work here */
   }
}

 

         Many languages automatically add a public default constructor if you don’t specify any

         Abstract classes get a protected constructor

         These two code snippets are equivalent:

public class Foo {

}

public class Foo {

   public Foo () {}

}

 

         Always explicitly add a default constructor to avoid versioning issues

         Adding a new constructor removes the default one, breaking clients

// V1

public class Foo {

}

Calling Code works: Foo f = new Foo()

 

// V2

public class Foo {
  public Foo (int value)

}

Calling code breaks: Foo f = new Foo()

 

Method Usage

 

         Use overloading only when the overloads do semantically the same thing

         Incorrect overload:

String.IndexOf(string value) {}

String.IndexOf(char[] anyOf) {}

 

         Correct overload:

Convert.ToString(int value) {}

Convert.ToString(double value) {}

 

         Used to avoid boxing

        Write(object) works for any type

        But specialization avoids boxing

        Do only when completely special casing

public static void Write (bool value);
public static void Write (int value);
public static void Write (double value);
public static void Write (object value);

 

         Use appropriate default values

         Simple method assumes default state

         More complex methods indicate changes from the default state

MethodInfo Type.GetMethod (string name);
    //ignoreCase = false

MethodInfo Type.GetMethod (string name,
    boolean ignoreCase);

         Use a zeroed state for the default value (such as: 0, 0.0, false, “”, etc.)

         Be consistent in the ordering and naming of method parameters

         Only the method with the most parameters should be virtual if needed

public class Foo {
   private const string defaultForA = "a default";
   private const int defaultForB = 42;
   public void Bar(){
      Bar(defaultForA, defaultForB);
   }
   public void Bar (string a){
      Bar(a, defaultForB);
   }
   public /*virtual*/ void Bar (string a, int b){
      // core implementation here
   }
}

 

         Variable number of arguments (e.g. printf)

         Use params

public static string Format(string format,

     params object[] args);

 

         Not used for in/out params (e.g. scanf)

         Only provide overloads for performance reasons IF you special case each code path

 

void Format (string formatString, object arg1)

void Format (string formatString, object arg1, object arg2)

void Format (string formatString, params object [] args)

 

 

         Allowing method inlining by the JIT

         Minimize the use of virtual methods

         Don’t write really large methods

         Don’t have large numbers of locals

More to come...