关于 LINQ 和 Lambda 重新查询的问题

发布于 2024-07-29 02:09:02 字数 846 浏览 2 评论 0原文

我对 LINQ 和 Lambda 查询的结果有疑问。 例如,我有以下代码:

class ClassA<T> {
     public string Name { get; set; }
     public T ObjectT { get; set; }
}

List<ClassA<T>> list;
// list is populated
// First way to get instance from list, reference type?
ClassA<T> instance1 = list.Select(x=> x).Where(x=>x.Name == "A").
  FirstOrDefault();
// Second way to clone or copy instance from the list
ClassA<T> instance2 = list.Select(x=> 
  new ClassA<T> { Name = x.Name, ObjectT = x.ObjectT}).
  Where( x=> x.Name = "A").FirstOrDefault();

显然,instance2 是列表中找到的实例的克隆或副本。 实例1怎么样? 这是一个新实例还是只是对列表中实例的引用? 如果instance1是对列表项的对象引用,则对其属性的任何更改都可能会更改列表中的同一对象。 是对的吗?

如果是这种情况,并且我不想对列表中的对象产生任何隐式影响,我认为我应该使用第二种策略。 但是,如果我确实希望检索到的实例中的任何更改也在列表中具有相同的更改,我应该使用策略 1。不确定我的理解是否正确。 任何意见?

I have a question about the result of LINQ and Lambda query. For example, I have the following codes:

class ClassA<T> {
     public string Name { get; set; }
     public T ObjectT { get; set; }
}

List<ClassA<T>> list;
// list is populated
// First way to get instance from list, reference type?
ClassA<T> instance1 = list.Select(x=> x).Where(x=>x.Name == "A").
  FirstOrDefault();
// Second way to clone or copy instance from the list
ClassA<T> instance2 = list.Select(x=> 
  new ClassA<T> { Name = x.Name, ObjectT = x.ObjectT}).
  Where( x=> x.Name = "A").FirstOrDefault();

It is obviously that instance2 is a clone or copy of an instance found in list. How about instance1? Is this one a new instance or just a reference to an instance in the list? If instance1 is an object reference to list's item, any change to its property may change the same object in the list. Is that right?

If that's the case and I don't want to have any implicit effect on objects in the list, I think I should use the second strategy. However, if I do want any changes in the retrieved instances also have the same changes in the list, I should use strategy 1. Not sure if my understanding is correct. Any comments?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

何以心动 2024-08-05 02:09:02

它将是对列表中对象的引用。 您可以做的是使用 Clone() 函数创建一个副本,该函数返回重复的结果,导致代码

list.Where(x => x.Name == "A").FirstOrDefault().Clone()

注意 Select(x => x) 是不必要的。 克隆将是一种扩展方法,类似于

public static ClassA<T> Clone<T>(this ClassA<T> self) {
    if (self == null) return null;
    return new ClassA { 
        Name = self.Name,
        ObjectT = self.ObjectT
    }
}

it will be a reference to the object in the list. What you could do, is create a copy using a Clone() function that returns a duplicate resulting in the code

list.Where(x => x.Name == "A").FirstOrDefault().Clone()

Note that Select(x => x) is unnecessary. Clone would be an extension method along the lines of

public static ClassA<T> Clone<T>(this ClassA<T> self) {
    if (self == null) return null;
    return new ClassA { 
        Name = self.Name,
        ObjectT = self.ObjectT
    }
}
清浅ˋ旧时光 2024-08-05 02:09:02

由于您的 ClassA 是一个 class (而不是 struct),因此 instance1 是对同一类的引用列表内的对象。

关于策略,如果您不希望列表的用户能够弄乱列表元素,我建议使用以下替代方案:

  • Make ClassA a 结构。 这样,任何查询都将返回列表中元素的副本;

  • 使 ClassA 实现如下所示的 IClonable,并在传递给不可信代码之前克隆它。

请注意,ObjectT 属性可能是一个类。 因此,即使在克隆 ClassA 对象之后,ObjectT 属性也将是对同一对象的引用,并且任何用户代码都可以修改它。 也许,您还需要克隆 ObjectT


class ClassA<T> : ICloneable
{
     public string Name { get; set; }
     public T ObjectT { get; set; }

     public ClassA<T> Clone()
     {
         return (ClassA<T>)this.MemberwiseClone();
     }

     object ICloneable.Clone()
     {
         return this.Clone();
     }
}

正如建议的,您可以使用扩展方法来避免空引用问题。 正如您所看到的,该问题有多种解决方案。 您应该选择更适合您的具体问题的一种。

static class CloneableExt
{
    public static T CloneNull<T>(this T obj) where T : class, ICloneable
    {
        if (obj == null) return null;
        return (T)obj.Clone();
    }
}

编辑1:添加了CloneableExt

Since your ClassA<T> is a class (not a struct), instance1 is a reference to the same object that is inside the list.

About the strategy, if you didn't want the users of your list to be able to mess around the list elements, I would suggest these alternatives:

  • Make ClassA<T> a struct. This way any query will return copy of the elements in the list;

  • Make ClassA<T> implement IClonable like below, and clone it before passing to a untrustworthy code.

Beware that the ObjectT property might be a class. So, even after you clone the ClassA<T> object, the ObjectT property will be a reference to the same object, and any user code will be able to modify it. Maybe, you'll need to clone ObjectT too;


class ClassA<T> : ICloneable
{
     public string Name { get; set; }
     public T ObjectT { get; set; }

     public ClassA<T> Clone()
     {
         return (ClassA<T>)this.MemberwiseClone();
     }

     object ICloneable.Clone()
     {
         return this.Clone();
     }
}

As suggested, you could use an extension method to avoid null reference problems. As you can see, there are several solutions to the problem. You should choose the one that better fit to your specific problem.

static class CloneableExt
{
    public static T CloneNull<T>(this T obj) where T : class, ICloneable
    {
        if (obj == null) return null;
        return (T)obj.Clone();
    }
}

EDIT 1: CloneableExt added

她比我温柔 2024-08-05 02:09:02

是的,第一个查询不会克隆列表中的对象,因此 instance 将引用 list 中的实际对象。 第二个查询显式构造对象的克隆。

Yes, the first query doesn't clone the objects in the list, so instance will reference the actual object from list. The second query explicitly constructs a clone of the object.

醉梦枕江山 2024-08-05 02:09:02

您在第二个示例中所做的是浅表复制,这是一个新实例,但其引用类型成员仍被引用。

为了正确地做到这一点,你应该实现 ICloneable:

class ClassA<T> : System.ICloneable where T : System.ICloneable
    {
        public string Name { get; set; }
        public T ObjT { get; set; }


        public object Clone()
        {
            var clone = new ClassA<T>();
            clone.Name = (string)Name.Clone();
            clone.ObjT = (T)ObjT.Clone();
            return clone;
        }
    }

然后

ClassA<T> instance2 = list.Where( x=> x.Name == "A").First().Clone();

What you do in your second example is a shallow copy, that is a new Instance but with its refernce type members still refensced.

To do it properly you should implement ICloneable:

class ClassA<T> : System.ICloneable where T : System.ICloneable
    {
        public string Name { get; set; }
        public T ObjT { get; set; }


        public object Clone()
        {
            var clone = new ClassA<T>();
            clone.Name = (string)Name.Clone();
            clone.ObjT = (T)ObjT.Clone();
            return clone;
        }
    }

and then

ClassA<T> instance2 = list.Where( x=> x.Name == "A").First().Clone();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文