[英]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.