Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 扩展方法没有设置值_C#_Extension Methods - Fatal编程技术网

C# 扩展方法没有设置值

C# 扩展方法没有设置值,c#,extension-methods,C#,Extension Methods,我有一个产品类,看起来像这样- public class Product { public int ProductId { get; set; } public string Name { get; set; } } 我有一个像这样的扩展类 public static class ProductExtension { public static void FixProduct(this Product product) { product = n

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

public class Product
{
    public int ProductId { get; set; }
    public string Name { get; set; }
}
我有一个像这样的扩展类

public static class ProductExtension
{
    public static void FixProduct(this Product product)
    {
        product = new Product(){Name = product.Name.ToUpper()};
        //product.Name is now UPPERCASE
    }
}
在我的主要方法中,我有-

static void Main(string[] args)
{
    Product p = new Product() {ProductId = 1, Name = "steve"};
    p.FixProduct(); 
    System.Console.WriteLine(p.Name);
}
它打印的是
“steve”
,而不是我希望它打印的内容:
“steve”

为什么扩展方法中的赋值不起作用?

扩展方法不能这样使用。在方法中,创建
Product
的新实例,然后将其分配给
Product
,这是对传递对象的本地引用,而不是原始引用
p

当您第一次进入函数时,您有两个引用引用内存中的同一对象

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

解决方案:

  • 要纠正这一点并使其与您试图做的最接近, 更改方法以获取
    ref
    参数:

    public static void FixProduct(ref Product product)
    {
        product = new Product() { Name = product.Name.ToUpper() };
        //product.Name is now UPPERCASE
    }
    
    然后:

    ProductExtension.FixProduct(ref p);
    
  • 我相信更好的方法是(通过 成员函数或扩展方法)来更新对象 实例化一个新的实例:

    public static void FixProduct(this Product product)
    {
        product.Name = product.Name.ToUpper();
    }
    

  • 在扩展方法中,您将为变量
    Product
    分配一个新的
    Product
    。这不会影响原始引用的
    产品

    将该方法修改为下面的方法,以设置原始传入对象的名称

    public static void FixProduct(this Product product)
    {
        product.Name = product.Name.ToUpper();
    }
    

    我建议按照一个模式做一个小小的改变。将新产品退回,而不是
    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
        }
    }
    
    然后像这样使用它:

    static void Main(string[] args)
    {
        var p = new Product()
            {
                ProductId = 1, 
                Name = "steve"
            }
            .FixProduct();
        System.Console.WriteLine(p.Name);
    }
    
    这种方法的一个显著优点是(如果您认为需要),您可以支持多个产品类,同时保留它们的精确类型,例如:

    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
                }
        }
    }
    
    另一方面,如果您只想“修复”产品名称,那么您可以将其包装在属性中

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

    …然后您根本不需要扩展方法。

    参数按值传递,除非它们是
    ref
    out
    <代码>此不会改变这一点。您可以从语法上理解这一点,因为
    ref
    out
    需要;否则,只需要一个

    不幸的是,您不能将
    参考
    输出
    组合

    您可以更改任何参数变量的值,但是,除了
    ref
    out
    的情况外,最好避免或限制对传入值进行快速润色,以简化以后的算法代码

    允许使用方法为值参数指定新值。这样的 分配仅影响由表示的本地存储位置 值参数它们对中给定的实际参数没有影响 方法调用。 -


    因此,分配确实有效,只是不是以
    ref
    out
    的方式。

    FixProduct
    中创建
    Product
    的新实例。它将被GC删除,不会影响原始对象
    product=new product()
    重定向变量以引用新对象,而不是作为参数传入的对象(而且它也应该是不必要的,为什么不干脆
    product.Name=
    )您需要将
    此产品
    作为
    ref
    参数传递,以便在扩展方法之外反映其值的更改。然而,扩展方法。您可以使用诸如
    var p=new Product{ProductId=1,Name=“steve”}.FixProduct()之类的函数
    为什么否决?一个更优雅的方法是将它放在原始的
    产品
    类中(如果可能的话),例如
    Product.Fix(prod)@IanH.-我同意,或者仍然使用扩展方法,但只是更新对象而不是创建新的one@Bryan-不客气:)我建议使用我听过的第二种解决方案。我想在我写答案时,你在编辑你的帖子。我也这么做了,但是让一个扩展方法返回它正在扩展的类型感觉有点奇怪。不,这很常见。事实上,所有LINQ扩展方法都使用此模式,以及遵循生成器模式的对象,例如大多数IoC容器。让人感觉产品是不可变的,就像对字符串执行操作一样。我必须一直和LINQ在一起,我已经习惯了,我想这只是一个例子,还有更多的事情要做。但是如果你只是想强制名字大写,也许可以用一个属性来包装——我会在最后编辑我的答案来提出这个建议。这是对我真正做的事情的一个粗略简化,但它已经验证了我最初尝试的是不可行的。谢谢你的建议。
    
    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
        }
    }