使用扩展方法实例化类的实例

时间:2009-05-12 12:01:10

标签: c# extension-methods

此代码背后的想法是,如果该类设置为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的处理方式是什么?据推测它只是垃圾收集......

EDIT2

好的,我们回到这里的基础知识。请考虑以下代码:

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的任何更改。

4 个答案:

答案 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();
    }
}
相关问题