Brad Abrams
You asked for it, you got it.. feedback always welcome.
Attribute Usage
?FONT face="Times New Roman" size=1 Suffix with 揂ttribute?O:P
?FONT face="Times New Roman" size=1 Perf tip: seal attribute classes for faster runtime lookup
?FONT face="Times New Roman" size=1 Specify the AttributeUsage attribute completely
?FONT face="Times New Roman" size=1 Don抰 rely on the defaults!
?FONT face="Times New Roman" size=1 Be as restrictive as possible
?FONT face="Times New Roman" size=1 You can always open it up later
[AttributeUsage(
AttributeTargets.All,
Inherited = true,
AllowMultiple = false)]
?FONT face="Times New Roman" size=1 AttributeTargets ?where is the attribute allowed to be applied?
?FONT face="Times New Roman" size=1 Inherited ?should derived members/types be considered to have this attribute?
?FONT face="Times New Roman" size=1 AllowMultiple ?Is it legal to put more than one instance of the attribute on a particular member?
?FONT face="Times New Roman" size=1 Use constructor arguments for required parameters (positional arguments)
?FONT face="Times New Roman" size=1 Provide a read-only property with the same name
?FONT face="Times New Roman" size=1 Use read-write properties for optional parameters (named arguments)
?FONT face="Times New Roman" size=1 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
?FONT face="Times New Roman" size=1 Static classes contain just static members
?FONT face="Times New Roman" size=1 Compromise between pure OO design with usability
?FONT face="Times New Roman" size=1 Commonly used for
?FONT face="Times New Roman" size=1 Shortcuts for other operations (System.IO.File)
?FONT face="Times New Roman" size=1 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 {..}
}
}
?FONT face="Times New Roman" size=1 Best used when:
?FONT face="Times New Roman" size=1 Clear charter for the class
?FONT face="Times New Roman" size=1 Not a 搈iscellaneous?bucket
?FONT face="Times New Roman" size=1 Not the center point of a design
?FONT face="Times New Roman" size=1 Use sparingly
?FONT face="Times New Roman" size=1 Watch out for disconnected design
?FONT face="Times New Roman" size=1 Static classes
?FONT face="Times New Roman" size=1 Are sealed
?FONT face="Times New Roman" size=1 Have private default constructor
?FONT face="Times New Roman" size=1 No instance members
?FONT face="Times New Roman" size=1 Static Classes: Bad Design
?FONT face="Times New Roman" size=1 Late in the final milestone we added a method to tell if the runtime is being shut down
?FONT face="Times New Roman" size=1 However we added the method as an instance method making it completely uncallable
?FONT face="Times New Roman" size=1 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---
}
?FONT face="Times New Roman" size=1
Constructors
?FONT face="Times New Roman" size=1 Do minimal work in the constructor
?FONT face="Times New Roman" size=1 Only capture the parameters
?FONT face="Times New Roman" size=1 Cost is delayed
?FONT face="Times New Roman" size=1 You can throw exceptions from constructors
?FONT face="Times New Roman" size=1 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 */
}
}
?FONT face="Times New Roman" size=1 Many languages automatically add a public default constructor if you don抰 specify any
?FONT face="Times New Roman" size=1 Abstract classes get a protected constructor
?FONT face="Times New Roman" size=1 These two code snippets are equivalent:
public class Foo {
}
public class Foo {
public Foo () {}
}
?FONT face="Times New Roman" size=1 Always explicitly add a default constructor to avoid versioning issues
?FONT face="Times New Roman" size=1 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
?FONT face="Times New Roman" size=1 Use overloading only when the overloads do semantically the same thing
?FONT face="Times New Roman" size=1 Incorrect overload:
String.IndexOf(string value) {}
String.IndexOf(char[] anyOf) {}
?FONT face="Times New Roman" size=1 Correct overload:
Convert.ToString(int value) {}
Convert.ToString(double value) {}
?FONT face="Times New Roman" size=1 Used to avoid boxing
?FONT face="Times New Roman" size=1 Write(object) works for any type
?FONT face="Times New Roman" size=1 But specialization avoids boxing
?FONT face="Times New Roman" size=1 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);
?FONT face="Times New Roman" size=1 Use appropriate default values
?FONT face="Times New Roman" size=1 Simple method assumes default state
?FONT face="Times New Roman" size=1 More complex methods indicate changes from the default state
MethodInfo Type.GetMethod (string name);
//ignoreCase = false
MethodInfo Type.GetMethod (string name,
boolean ignoreCase);
?FONT face="Times New Roman" size=1 Use a zeroed state for the default value (such as: 0, 0.0, false, 摂, etc.)
?FONT face="Times New Roman" size=1 Be consistent in the ordering and naming of method parameters
?FONT face="Times New Roman" size=1 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
}
}
?FONT face="Times New Roman" size=1 Variable number of arguments (e.g. printf)
?FONT face="Times New Roman" size=1 Use params
public static string Format(string format,
params object[] args);
?FONT face="Times New Roman" size=1 Not used for in/out params (e.g. scanf)
?FONT face="Times New Roman" size=1 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)
?FONT face="Times New Roman" size=1 Allowing method inlining by the JIT
?FONT face="Times New Roman" size=1 Minimize the use of virtual methods
?FONT face="Times New Roman" size=1 Don抰 write really large methods
?FONT face="Times New Roman" size=1 Don抰 have large numbers of locals
More to come...