简体   繁体   English

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

[英]Instantiating an instance of a class using an extension method

The idea behind this code is that it uses an extension method to instantiate an instance of a class if that class is set to null. 这段代码背后的想法是,如果该类设置为null,它使用扩展方法来实例化类的实例。 The code is simple enough, but does not work (it compiles and runs, but at the end the object reference is still null ). 代码很简单,但不起作用(它编译并运行,但最后对象引用仍为null )。

Can anyone suggest why? 谁有人建议为什么?

The following code uses a simple class SomeClass that has a single string property. 以下代码使用具有单个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??
    }
}

(The discussion about whether or not this is an appropriate use of an extension method should be considered outside the scope of the question! I am interested in understanding why this approach does not work) (关于这是否适当使用扩展方法的讨论应该被认为超出了问题的范围!我有兴趣理解为什么这种方法不起作用)

Edit 编辑

On closer inspection this question is less about extension methods, and more about what is going on when you pass a reference type with or without the ref keyword. 仔细观察这个问题不是关于扩展方法的问题,而是关于在传递带有或不带ref关键字的引用类型时发生的事情的更多信息。

The following function will cause a passed obj to be initialised for the caller: 以下函数将导致为调用者初始化传递的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

The following function will not cause a passed obj to be initlaised for the caller: 以下函数不会导致为调用者初始化传递的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

But...we're dealing with a reference type here, so what does the CLR do with the new d obj if the ref keyword is not used? 但是......我们在这里处理一个引用类型,那么如果不使用ref关键字,CLR对new d obj做了什么? Presumably it just gets garbage collected... 据推测它只是收集垃圾......

Edit2 EDIT2

OK, we're going back to basics here. 好的,我们回到这里的基础知识。 Consider the code below: 请考虑以下代码:

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"
    }
}

Note: someClass was not passed using the ref keyword, but the value of its property was still changed for the caller. 注意: someClass未使用ref关键字传递,但其属性的值仍然为调用者更改。 This is what I would expect to see. 这是我期望看到的。

However, change the SetProperty function as follows: 但是,更改SetProperty函数如下:

static void SetProperty(SomeClass someClass)
{
    someClass = new SomeClass { SomeProperty = "Bar" };
}

...and the caller will not see any change to someClass . ...并且调用者不会看到someClass任何更改。

You would need to return the value; 你需要返回值; extension methods aren't ref on the this argument: 扩展方法不是对this参数的ref

static class ExtensionMethods
{
    public static T InitialiseObjectIfNull<T>(this T obj)
        where T : class, new()
    {
        return obj ?? new T();            
    }
}

Then you'd need: 然后你需要:

someClass = someClass.InitialiseObjectIfNull();

Personally, I expect it would be simpler to do it directly... with either: 就个人而言,我希望直接做到这一点会更简单...:

if(someClass == null) someClass = new SomeClass();

or 要么

someClass = someClass ?? new SomeClass();

this T obj would need to be a ref argument. this T obj需要是一个ref参数。 Since that's not allowed ( MSDN or C# In Depth p258, Skeet), you can't. 由于这是不允许的( MSDN或C#In Depth p258,Skeet),你不能。

I would suggest you not push this idea too far, though. 不过,我建议你不要把这个想法推得太远。 It seems like a confusing application of extension methods, especially when the alternative is still a short one line. 这似乎是扩展方法的一个令人困惑的应用,特别是当替代方案仍然是一个短的一行。

Extension method is just syntactic sugar to this: 扩展方法只是语法糖:

ExtensionMethods.InitialiseObjectIfNull(someClass);

You're passing someClass by value, thus assigning to it inside InitialiseObjectIfNull body will have no effect unless you pass someClass by reference, which you can't do in case of extension methods: you cannot pass this in this T obj by reference. 你通过值传递someClass ,因此在InitialiseObjectIfNull体内分配它将没有任何效果,除非你通过引用传递someClass ,在扩展方法的情况下你不能这样做:你不能通过引用在this T obj传递this

This doesn't work because the obj parameter is not declared passed by reference. 这不起作用,因为obj参数未声明通过引用传递。 Unfortunately, you can't declare a parameter as "this ref T obj", it's not supported... I know, I tried that yesterday ;) 不幸的是,你不能将参数声明为“this ref T obj”,它不受支持......我知道,我昨天试过了;)

You could do something like that instead : 你可以这样做:

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