此代码背后的想法是,如果该类设置为null,它使用扩展方法来实例化类的实例。代码很简单,但不起作用(它编译并运行,但最后对象引用仍为null
)。
任何人都可以建议为什么?
以下代码使用具有单个SomeClass
属性的简单类string
。
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
但是......我们在这里处理引用类型,那么如果不使用new
关键字,CLR对obj
d ref
的处理方式是什么?据推测它只是垃圾收集......
好的,我们回到这里的基础知识。请考虑以下代码:
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
的任何更改。
答案 0 :(得分:6)
你需要返回值; ref
参数上的扩展方法不是this
:
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();
答案 1 :(得分:5)
this T obj
需要是ref
参数。由于这是不允许的(MSDN或C#In Depth p258,Skeet),你不能。
但我建议你不要把这个想法推得太远。这似乎是扩展方法的一个令人困惑的应用,特别是当替代方案仍然是一个短的一行时。
答案 2 :(得分:4)
扩展方法只是语法糖:
ExtensionMethods.InitialiseObjectIfNull(someClass);
您按值传递someClass
,因此在InitialiseObjectIfNull
正文中分配它将无效,除非您通过引用传递someClass
,如果是扩展方法:您无法通过引用在this
中传递this T obj
。
答案 3 :(得分:2)
这不起作用,因为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();
}
}