【问题标题】:Does List.First() returns a new instance?List.First() 是否返回一个新实例?
【发布时间】:2015-04-10 15:07:10
【问题描述】:

我看到的行为与我对 List.First() 的预期不同:

我构建了一些包含列表的测试应用程序

 public abstract class GridTemplateModelBase : INotifyPropertyChanged, IDisposable
    {
Public ObservableCollection<ColumnModel> Columns
        {
            get
            {
                return _columns;
            }
            protected set
            {
                _columns = value;
                OnPropertyChanged();
            }
        }
}

ColumnModel 类包含一个名为 GroupIndex 的属性。我想从Columns 列表中选择特定项目并通过另一个类设置GroupIndex 属性,所以我使用了以下代码:

  //choose the list item I want to change
  var test = GridProfile.Columns.First(p => p.FieldName == item);
  //Change GroupIndex value
  test.GroupIndex = 1;

我希望这段代码能够更改列表项的GroupIndex 值,但似乎`Columns.First()' 方法返回了此列表项的副本。 请看以下图片:

所选列表项的初始 GroupIndex 为 -1

在 GroupIndex 值改变后测试上面代码中的参数值,你可以看到它变成了 1

运行上述代码后所选列表项的值 => 仍然是 -1

如果List.First() 方法返回所选列表项的引用,我们必须看到该列表项的值与上面代码中的test 参数相同,但令人惊讶的是,情况并非如此。

有人能解释一下Linq.First() 方法的工作原理吗?

希望我的问题很清楚


这是ColumnModel类的内容:

public class ColumnModel : INotifyPropertyChanged
    {
        /// <summary>
        /// Initializes a new instance of the ColumnModel class.
        /// </summary>
        public ColumnModel()
        {
            AllowEdit = DefaultBoolean.True;
            SortIndex = -1;
            GroupIndex = -1;
        }


        private string _cellToolTip;
        private int _sortIndex;
        private ColumnSortOrder _sortOrdering;
        private bool _isReadOnly;
        private int _groupIndex;
        private bool _isVisible;
        private bool _fixedWidth;
        private double _minWidth;
        private double _width;
        private EditSettingsHorizontalAlignment _cellContentAlighnment;
        private ColumnProfile _profileTemplate;
        private string _fieldHeader;
        private string _fieldName;
        private DefaultBoolean allowEdit;


        // Specifies the name of a data source field to which the column is bound. 
        public string FieldName
        {
            get
            {
                return _fieldName;
            }
            set
            {                
                _fieldName = value;
                OnPropertyChanged();
            }
        }

        public string FieldHeader
        {
            get
            {
                return _fieldHeader;
            }
            set
            {
                _fieldHeader = value;
                OnPropertyChanged();
            }
        }

        // Specifies the type of template to load
        public ColumnProfile ProfileTemplate
        {
            get
            {
                return _profileTemplate;
            }
            set
            {
                _profileTemplate = value;
                OnPropertyChanged();
            }
        }

        public EditSettingsHorizontalAlignment CellContentAlighnment
        {
            get
            {
                return _cellContentAlighnment;
            }
            set
            {
                _cellContentAlighnment = value;
                OnPropertyChanged();
            }
        }

        public double Width
        {
            get
            {
                return _width;
            }
            set
            {
                _width = value;
                OnPropertyChanged();
            }
        }

        public double MinWidth
        {
            get
            {
                return _minWidth;
            }
            set
            {
                _minWidth = value;
                OnPropertyChanged();
            }
        }

        public bool FixedWidth
        {
            get
            {
                return _fixedWidth;
            }
            set
            {
                _fixedWidth = value;
                OnPropertyChanged();
            }
        }

        public bool IsVisible
        {
            get
            {
                return _isVisible;
            }
            set
            {
                _isVisible = value;
                OnPropertyChanged();
            }
        }

        public int GroupIndex
        {
            get
            {
                return _groupIndex;
            }
            set
            {
                _groupIndex = value;
                OnPropertyChanged();
            }
        }

        public bool IsReadOnly
        {
            get
            {
                return _isReadOnly;
            }
            set
            {
                _isReadOnly = value;
                OnPropertyChanged();
            }
        }

        public ColumnSortOrder SortOrdering
        {
            get
            {
                return _sortOrdering;
            }
            set
            {
                _sortOrdering = value;
                OnPropertyChanged();
            }
        }


        public DefaultBoolean AllowEdit
        {
            get { return allowEdit; }
            set
            {
                allowEdit = value;
                OnPropertyChanged();
            }
        }

        public string CellToolTip
        {
            get
            {
                return _cellToolTip;
            }
            set
            {
                _cellToolTip = value;
                OnPropertyChanged();
            }
        }


        public int SortIndex
        {
            get
            {
                return _sortIndex;
            }
            set
            {
                _sortIndex = value;
                OnPropertyChanged();
            }
        }        
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

更新: 通过您的 cmets,我了解到 List.First() 返回引用类型,可能我的代码包含问题或者我的调试器可能返回错误结果 - 将检查它。

这里是First 源代码(来源:@Enigmativity):

public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
  if (source == null)
    throw Error.ArgumentNull("source");
  if (predicate == null)
    throw Error.ArgumentNull("predicate");
  foreach (TSource source1 in source)
  {
    if (predicate(source1))
      return source1;
  }
  throw Error.NoMatch();
}

谢谢

【问题讨论】:

  • 我怀疑这会复制你的对象 - 我宁愿认为你的 GroupIndex 设置器可能有问题(它真的设置了_groupIndex)吗?
  • @CarstenKönig - 是的,二传手很好,我仔细检查了这个
  • 发布ColumnModel 课程。真的可以是struct吗?
  • @JonEgerton 正如我所提到的,它是一个引用类型 - 请参阅我的帖子 - 添加了 ColumnModel
  • 什么是选定列表项?正如我在您的图片中看到的,您的代码将test.GroupIndex 更改为1。您比较过FieldName 属性吗?也许在您的收藏中,您有多个具有相同FieldName 的项目?也许您的 选定列表项 根本不在 GridProfile.Columns 中。您的问题现在无法为其他任何人解决。 First() 不会创建副本,因此您的问题不在您发布的代码范围内。

标签: c# linq


【解决方案1】:

.First(x =&gt; ...) 反编译如下:

public static TSource First<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
  if (source == null)
    throw Error.ArgumentNull("source");
  if (predicate == null)
    throw Error.ArgumentNull("predicate");
  foreach (TSource source1 in source)
  {
    if (predicate(source1))
      return source1;
  }
  throw Error.NoMatch();
}

它显然返回了实际实例(如果 source 是引用类型)。

您的代码中肯定发生了其他事情。

【讨论】:

    【解决方案2】:

    根据this问题和选择的答案,取决于对象的值/引用类型:

    如果它们是类,则实例相同,但如果它们是结构/值类型,则复制。

    请注意您在 Visual Studio 中看到的有关 lambda 表达式的信息,根据您使用的版本,调试可能不会 100% 正确实现。不知道这里是不是这样。

    【讨论】:

      【解决方案3】:

      它返回指定序列中的第一个元素,而不是新实例。所以这是存储在集合中的原始对象。 https://msdn.microsoft.com/en-us/library/vstudio/bb291976(v=vs.100).aspx 你能发布 ColumnModel 类吗?

      【讨论】:

      • 添加ColumnModel类内容
      • 请不要发布问题/cmets 作为答案 - 谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-18
      • 1970-01-01
      • 2016-01-21
      相关资源
      最近更新 更多