[英]Instantiating an instance of a class using an extension method
這段代碼背后的想法是,如果該類設置為null,它使用擴展方法來實例化類的實例。 代碼很簡單,但不起作用(它編譯並運行,但最后對象引用仍為null
)。
誰有人建議為什么?
以下代碼使用具有單個string
屬性的簡單類SomeClass
。
class SomeClass
{
public string SomeProperty { get; set; }
}
static class ExtensionMethods
{
public static void InitialiseObjectIfNull<T>(this T obj)
where T : class, new()
{
if (obj == null) obj = new T();
}
}
class Program
{
static void Main(string[] args)
{
SomeClass someClass = null;
someClass.InitialiseObjectIfNull();
// someClass is still null - but why??
}
}
(關於這是否適當使用擴展方法的討論應該被認為超出了問題的范圍!我有興趣理解為什么這種方法不起作用)
仔細觀察這個問題不是關於擴展方法的問題,而是關於在傳遞帶有或不帶ref
關鍵字的引用類型時發生的事情的更多信息。
以下函數將導致為調用者初始化傳遞的obj
:
static void InitialiseObjectIfNull<T>(ref T obj) where T : class, new()
{
if (obj == null) obj = new T();
}
InitialiseObjectIfNull<SomeClass>(ref someClass); // someClass will be initialised
以下函數不會導致為調用者初始化傳遞的obj
:
static void InitialiseObjectIfNull<T>(T obj) where T : class, new()
{
if (obj == null) obj = new T();
}
InitialiseObjectIfNull<SomeClass>(someClass); // someClass will not be initialised
但是......我們在這里處理一個引用類型,那么如果不使用ref
關鍵字,CLR對new
d obj
做了什么? 據推測它只是收集垃圾......
好的,我們回到這里的基礎知識。 請考慮以下代碼:
class Program
{
static void SetProperty(SomeClass someClass)
{
someClass.SomeProperty = "Bar";
}
static void Main(string[] args)
{
SomeClass someClass = new SomeClass { SomeProperty = "Foo" };
SetProperty(someClass);
// someClass.SomeProperty now equals "Bar"
}
}
注意: someClass
未使用ref
關鍵字傳遞,但其屬性的值仍然為調用者更改。 這是我期望看到的。
但是,更改SetProperty
函數如下:
static void SetProperty(SomeClass someClass)
{
someClass = new SomeClass { SomeProperty = "Bar" };
}
...並且調用者不會看到someClass
任何更改。
你需要返回值; 擴展方法不是對this
參數的ref
:
static class ExtensionMethods
{
public static T InitialiseObjectIfNull<T>(this T obj)
where T : class, new()
{
return obj ?? new T();
}
}
然后你需要:
someClass = someClass.InitialiseObjectIfNull();
就個人而言,我希望直接做到這一點會更簡單...:
if(someClass == null) someClass = new SomeClass();
要么
someClass = someClass ?? new SomeClass();
this T obj
需要是一個ref
參數。 由於這是不允許的( MSDN或C#In Depth p258,Skeet),你不能。
不過,我建議你不要把這個想法推得太遠。 這似乎是擴展方法的一個令人困惑的應用,特別是當替代方案仍然是一個短的一行。
擴展方法只是語法糖:
ExtensionMethods.InitialiseObjectIfNull(someClass);
你通過值傳遞someClass
,因此在InitialiseObjectIfNull
體內分配它將沒有任何效果,除非你通過引用傳遞someClass
,在擴展方法的情況下你不能這樣做:你不能通過引用在this T obj
傳遞this
。
這不起作用,因為obj參數未聲明通過引用傳遞。 不幸的是,你不能將參數聲明為“this ref T obj”,它不受支持......我知道,我昨天試過了;)
你可以這樣做:
static class ExtensionMethods
{
public static T InitialiseObjectIfNull<T>(this T obj)
where T : class, new()
{
return obj ?? new ();
}
}
class SomeClass
{
public string SomeProperty { get; set; }
}
class Program
{
static void Main(string[] args)
{
SomeClass someClass = null;
someClass = someClass.InitialiseObjectIfNull();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.