指定選擇性DateTime引數的預設值
8 |
選擇性引數(Optional Argument)是我愛用的C# 4.0新特性之一。
以傳入arg1, arg2引數的方法為例,若要讓arg2變成選擇性引數,過去得用多載(Overloading)實現,需要宣告成
void someMethod(string arg1) { someMethod(arg1, "arg2_default_value"); }
及
void someMethod(string arg1, string arg2) { ... }
兩個方法;而在C# 4.0只需宣告成
void someMethod(string arg1, string arg2 = "arg2_default_value")
就搞定,當有多個選擇性引數時,可省下一大堆額外的方法宣告,簡潔許多。
不過,當引數為DateTime型別時,則會遇到一個困擾。例如: 我想將sayHello的time引數改為選擇性,未提供時直接用DateTime.Now。
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
sayHello("Jeffrey", DateTime.Now);
Console.Read();
}
static void sayHello(string name, DateTime time)
{
Console.WriteLine(
"Hello {0}, the system time is {1:HH:mm:ss}.",
name, time);
}
}
}
依直覺,我們會寫成DateTime time = DateTime.Now
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
sayHello("Jeffrey");
Console.Read();
}
static void sayHello(string name, DateTime time = DateTime.Now)
{
Console.WriteLine(
"Hello {0}, the system time is {1:HH:mm:ss}.",
name, time);
}
}
}
但以上寫法無法編譯,會彈出"Default parameter value for 'time' must be a compile-time constant"錯誤,原因是選擇性引數預設值必須為編譯時就已確定的常數(Constant)。即便改用DateTime time = DateTime.MinValue當預設值,方法內部再用if (time == DateTime.MinValue) time = DateTime.Now;動態指定,依然行不通! 原因是DateTime.MinValue雖然是一個固定不動的值,但由於它是DateTime的一個唯讀欄位,並不符合編譯時期常數的要求。
針對這個問題,過去看到比較多的做法是將time由DateTime改為DateTime?,在一開始時設為null,在方法內部再透過if (time == null) time = DateTime.Now;,這方法可行,但有點美中不足: 當time的型別變成了DateTime?,後續需要用它做為其他方法的DateTime引數時,必須改用time.Value,直接給time會產生型別不符錯誤(因DateTime與DateTime?是兩種不同的型別)。
今天爬文學到一個關鍵字default(T),可用來處理泛型有時要給null(參考型別, Reference Type),有時要給0(實值型別, Value Type)的情境。而它恰巧也可應用在本案例中,宣告成DateTime time = default(DateTime)可以通過編譯,而其值等於DateTime.MinValue,故可用if (time == DateTime.MinValue) time = DateTime.Now;在方法內部進行後續處理,同時也維持time是DateTime型別,個人覺得是更好的解決方案。
程式範例如下:
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DateTime t = DateTime.Now.AddHours(1);
sayHello1("Jeffrey");
sayHello1("Jeffrey", t);
sayHello2("Jeffrey");
sayHello2("Jeffrey", t);
Console.Read();
}
//解法1: 將參數改為Nullable<DateTime>
static void sayHello1(string name, DateTime? time = null)
{
if (time == null) time = DateTime.Now;
Console.WriteLine(
"Hello {0}, the system time is {1:HH:mm:ss}.",
name, time);
//缺點: 後續應用在限定DateTime型別的場合,得改寫成time.Value
DateTime time2 = time.Value.AddHours(2);
(new System.Globalization.TaiwanCalendar())
.GetDayOfMonth(time.Value);
}
//解法2: 利用default(DateTime) (其值相當於DateTime.MinValue)
static void sayHello2(string name, DateTime time = default(DateTime))
{
if (time == DateTime.MinValue) time = DateTime.Now;
Console.WriteLine(
"Hello {0}, the system time is {1:HH:mm:ss}.",
name, time);
//使用default(DateTime)時,time為DateTime型別,應用較方便
DateTime time2 = time.AddHours(2);
(new System.Globalization.TaiwanCalendar())
.GetDayOfMonth(time);
}
}
}
Comments
# by Allen Kuo
我剛才測試時,發現使用vs.net 2010, 新專案選.NET Framework 2.0, 寫sayHello2()其實也可以正常運作 static DateTime gettomorrow(DateTime dt = default(DateTime)) 難道這語法其實在2.0時就有了
# by Jeffrey
to Allen Kuo, 真的耶! 找到一篇文章http://blogs.us.sogeti.com/dmaher/2011/02/optional-and-named-parameters-for-net-20/ 其解釋為 The reason it works in .Net Framework 2.0, is because the CLR always supported optional parameters because of VB .Net. It is just that c# took a while to support that feature.
# by Leo
To Allen, 代位回答:default(T) 的確是 2.0 就有的語法。黑大上面留的 MSDN 連結,就是 VS2005 版本的說明。
# by Jeffrey
to Leo, 我猜Allen指的是Optional Argument,當初它被當成C# 4.0的亮點之一(http://weblogs.asp.net/scottgu/archive/2010/04/02/optional-parameters-and-named-arguments-in-c-4-and-a-cool-scenario-w-asp-net-mvc-2.aspx) 倒沒想到透過VS2010編譯,在.NET 2.0上也能支援。
# by Allen Kuo
沒錯,我的意思就是如此,最近也遇到二個怪問題 http://www.allenkuo.com/userfiles/article/2012q1/2012-3-3_12-11-49.png http://www.allenkuo.com/GenericArticle/view1283.aspx 跟我平時想的不同
# by Billy
回 Allen 的圖片: http://www.allenkuo.com/userfiles/article/2012q1/2012-3-3_12-11-49.png 因為 datatable 為reference type,傳進 doB 時加 row 改變的是同一個 object。但在傳進 doC 後 assign 新的 datatable,此時 doC 內的 dt 已只向新的 memory location,對外面的 datatable 並沒有影響。 可以參考黑大的 Self Test - Value Type vs Reference Type: http://blog.darkthread.net/post-2007-10-19-self-test-value-type-vs-reference-type.aspx http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx
# by 假面人生
謝謝你的網站,讓我學到好多知識
# by 偉恩嘎B
謝謝解惑!! 受益良多~~