繁体   English   中英

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

[英]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做了什么? 据推测它只是收集垃圾......

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

你需要返回值; 扩展方法不是对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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM