C#扩展方法是否会影响当前实例或返回相同类型的新对象?

时间:2014-04-11 21:33:44

标签: c# .net extension-methods

使用扩展方法扩展非静态类型时,是否在"这个"发生在扩展类的原始实例上,还是返回应用了这些更改的新实例?或者也可以这样做,具体取决于扩展方法的编写方式?

考虑这个示例扩展方法:

public static AddressEntity FromAddressLight(this AddressEntity addressEntity, AddressLight addressLight)
{
    if (addressLight == null)
    {
        return null;
    }

    var result = new AddressEntity
    {
        Id = addressLight.AddressId,
        AddressName = addressLight.AddressName,
        // other mapping conversions here
    };

    return result;
}

以下哪种方法可以解决这个问题?

AddressLight light = new AddressLight(); // assume constructor populates this
AddressEntity myEntity = new AddressEntity(); // this constructor does not populate anything

myEntity.FromAddressLight(light); // Will this cause myEntity take on the value of "result" in the extension method?...
myEntity = myEntity.FromAddressLight(light); // ... or is this needed to copy "result" into myEntity?

// ... and why is this not something Visual Studio allows? Does this not become a static member of the extended class?
myEntity = AddressEntity.FromAddressLight(light);

3 个答案:

答案 0 :(得分:5)

快速回答......这取决于。

您给出的示例返回AddressEntity的新实例,但没有理由不能返回相同的实例,这对于链接或完全不同的东西都很方便。

取决于你。

myEntity = myEntity.FromAddressLight(light);在您的示例中正确使用此方法。

并且myEntity = AddressEntity.FromAddressLight(light);不起作用,因为你正在调用静态方法而不是实例方法,即使这在静态声明中有点反直觉。

答案 1 :(得分:3)

这有点奇怪作为一种扩展方法(作为"普通"静态方法更有意义)但是这里按照你的行顺序(跳过前两个):

  1. 这无济于事。扩展方法返回一个新对象,该对象未分配给任何东西,因此超出范围并被垃圾收集。

  2. 这将完全符合您的想法,并且是唯一合理的"使用这种方法的方法。

  3. 这是不允许的,因为没有" AddressEntity"传递给函数。不明确(显然你只传递1个参数)或隐式(因为你使用了类型来访问它,而不是对象)。

  4. 特别是因为你试图做(3),我不会将这个函数作为扩展方法(它甚至不使用任何AddressEntity字段,那么为什么它采用那种类型?)并且相反,它是一种常规的静态方法。

    明确地回答你的问题(标题中):

    扩展方法不是特别的,它只有一个隐式参数("这个"参数)所以它在调用它时看起来不错。如果它返回一个新值,您将获得一个新值。如果你修改了"这个"参数,它修改现有的值。它实际上可以做到这两点没有问题。它完全取决于扩展方法的内容。

答案 2 :(得分:1)

一般来说,这是一种非常奇怪的扩展方法。考虑到扩展方法只是语法糖(正如其他人之前提到的那样),普通用户真的会期待发生以下两种情况之一:

  1. 我调用扩展方法并获得自己的修改版本。
  2. 我调用扩展方法并返回转换后的类型。
  3. 我认为第二个是你真正想要的:

    public static AddressEntity ToAddressEntity(this AddressLight obj)
    {
        return new AddressEntity
        {
            Id = obj.AddressId,
            AddressName = obj.AddressName,
            // other mapping conversions here
        };
    }
    

    请记住,扩展方法不是基于返回类型,而是基于this之后指定的类型。所以在这种情况下你可以做AddressEntity addEntity = SomeAddressLight.ToAddressEntity();。这也是你没有在任何BCL中看到模式FromSomething()的原因,因为在扩展方法的情况下,它感觉非常违反直觉。