扩展方法没有设置值

Bry*_*yan 2 c# extension-methods

我有一个看起来像这样的产品类 -

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我有一个看起来像这样的扩展类

public static class ProductExtension
{
    public static void FixProduct(this Product product)
    {
        product = new Product(){Name = product.Name.ToUpper()};
        //product.Name is now UPPERCASE
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的主要方法中,我有 -

static void Main(string[] args)
{
    Product p = new Product() {ProductId = 1, Name = "steve"};
    p.FixProduct(); 
    System.Console.WriteLine(p.Name);
}
Run Code Online (Sandbox Code Playgroud)

这打印"steve"而不是我想要打印的内容:"STEVE".为什么扩展方法中的赋值不起作用?

Joh*_* Wu 7

我建议进行一些小改动,以遵循流畅的界面模式.而不是void返回新产品.不要使用ref,这很奇怪.

public static class ProductExtension
{
    public static Product FixProduct(this Product input)
    {
        return new Product
            {
                Name = input.Name.ToUpper(),
                Id = input.Id
            }
        //product.Name is now UPPERCASE
    }
}
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

static void Main(string[] args)
{
    var p = new Product()
        {
            ProductId = 1, 
            Name = "steve"
        }
        .FixProduct();
    System.Console.WriteLine(p.Name);
}
Run Code Online (Sandbox Code Playgroud)

这种方法的一个优点是(如果您认为您将需要它),您可以支持多个产品类,同时保留其精确类型,例如:

public static class ProductExtension
{
    public static T FixProduct<T>(this T input) where T: Product, new
    {
        return new T
            {
                Name = input.Name.ToUpper(),
                Id = input.Id
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以在任何派生产品类上使用它,同时保持完全相同的语法.

class DeluxeProduct : Product
{ }

static void Main()
{
    var p = new DeluxeProduct
        {
            Id = 1,
            Name = "Steve"
        }
        .FixProduct();
    Console.WriteLine(p.GetType().Name)); //outputs "DeluxeProduct"
}
Run Code Online (Sandbox Code Playgroud)

另一方面,如果您想要做的只是"修复"产品的名称,您可以将其包装在属性中.

class Product
{
    private string _name;

    public int Id { get; set; }

    public string Name
    {
        get { return _name; }
        set { _name = value.ToUpper(); } //Automatically "fix" it the moment you set it
    }
}
Run Code Online (Sandbox Code Playgroud)

...然后你根本不需要扩展方法.


Gil*_*een 6

扩展方法不能以这种方式使用.在您的方法中,您创建一个新实例,Product然后将其分配给product传递对象的本地引用,而不是原始引用p.

当您第一次进入该函数时,您所拥有的是引用内存中相同对象的两个引用.

在此输入图像描述

然后在退出方法之前,您有两个对象,一个由每个引用引用,带有product引用,引用在方法调用结束时由GC清理的局部变量.

在此输入图像描述

解决方案:

  1. 要更正此问题并使其与您尝试执行的操作最接近,请更改方法以获取ref参数:

    public static void FixProduct(ref Product product)
    {
        product = new Product() { Name = product.Name.ToUpper() };
        //product.Name is now UPPERCASE
    }
    
    Run Code Online (Sandbox Code Playgroud)

    然后:

    ProductExtension.FixProduct(ref p);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 我相信一个更好的方法将(通过使用成员函数或扩展方法)更新对象而不是实例化新对象:

    public static void FixProduct(this Product product)
    {
        product.Name = product.Name.ToUpper();
    }
    
    Run Code Online (Sandbox Code Playgroud)