規定値を指示するキーワードdefault・演算子??

キーワードdefault、演算子??は、どちらも規定値を指示します。
キーワードdefaultはパラメータ型Tに対する規定値。
演算子??は「Null許容型→Null非許容型」の変換に対する規定値。

defaultキーワード

このキーワードは、参照型の場合には null を返し、数値の値型にはゼロを返します。

ジェネリック コードの default キーワード (C# プログラミング ガイド)

パラメータ化された型Tの規定値割り当てのために用意されたとのこと。パラメータ型Tについて、参照型か値型(さらに言えば数値型か構造型か)かわからないため、このキーワードを使って参照型/値型それぞれについて適切な規定値で振る舞わせましょう…ということかと。
動きを見る。

using System;
namespace ConsoleApplication1
{
    public struct MyStruct
    {
        public int x;
        public override string ToString() { return string.Format("MyStruct[x={0}]", x); }
    }
    public class MyClass
    {
        public int x;
        public override string ToString() { return string.Format("MyClass[x={0}]", x); }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            consoleOut<byte>();
            consoleOut<int>();
            consoleOut<decimal>();
            consoleOut<bool>();
            consoleOut<string>();
            consoleOut<MyStruct>();
            consoleOut<MyClass>();
            Console.ReadLine();
        }
        static void consoleOut<T>()
        {
            Console.WriteLine(
                        "{0}:{1}", 
                        typeof(T).Name, 
                        isDefaultNull<T>());
        }
        static string isDefaultNull<T>()
        {
            return default(T) == null ? " **null**" : default(T).ToString();
        }
    }
}

これで、実行結果がこう。

Byte:0
Int32:0
Decimal:0
Boolean:False
String: **null**
MyStruct:MyStruct[x=0]
MyClass: **null**

参照型(String・MyClass)は規定値としてnullが返っている。値型や構造型は初期化された値が返っている。

??演算子

?? 演算子は、左側のオペランドが null 値でない場合にはこのオペランドを返し、null 値である場合には右側のオペランドを返します。

?? 演算子 (C#)

現在の値が null である null 許容型に、null 非許容型を割り当てる場合、既定値を割り当てるには、?? 演算子を使用します。たとえば、int? x = null; int y = x ?? -1; と指定します。

null 許容型 (C#)

動きを見る。

using System;
namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            consoleOut("test", "test");
            consoleOut("string.Empty", string.Empty);
            consoleOut("null", null);
            Console.ReadLine();
        }
        static void consoleOut(string title, string val)
        {
            string v = val ?? "[Default]";
            Console.WriteLine("{0}:<{1}>", title, v);
        }
    }
}

で、実行結果がこう。

test:<test>
string.Empty:<>
null:<[Default]>
雑感

引数にとった値がnullだとしても、規定値で処理を進めるときに使えそう。
string.Emptyに対しても規定値適用するなら

string v = (string.IsNullOrEmpty(val)) ? "[Default]" : val;

と書くかな。