在C#匿名类型成员中是否可以别名?

时间:2013-12-23 15:15:21

标签: c# ms-project

我正在开发一个工具,使用.NET和Office.MSProject.Interop库在MSProject上自动执行某些任务。

假设我有类似的东西:

Project actvProject;
var taskInfoDic = actvProject.Tasks.Cast<Task>().Select(
            task => new
            {
                task.Guid,
                task.Name,
                task.Work,
                task.ActualWork,
                task.PercentWorkComplete,
                task.Start,
                task.Finish,
                task.Duration,
                task.Deadline
            }).ToDictionary(x => x.Guid);

 // More code that mutates actvProject and its Task members

如果我变异taskInfoDic,是否可以更改actvProject值(由actvProject对象的成员组成)?

匿名类型值不应该是不可变的吗?

3 个答案:

答案 0 :(得分:2)

您可以改变词典,因为词典是可变的。这意味着您可以添加全新的键/值对,或更改与键关联的值。您不能改变某些键指向的现有值对象(在这种情况下,因为词典值是不可变类型)。

您还在创建字典时复制原始数据源中的所有数据,您没有复制对任何值的引用,或以任何方式推迟执行,因此不会对其进行任何更改可以在新词典中观察到的源数据结构。

  

匿名类型值不应该是不可变的吗?

他们是。这并不意味着您放入的任何数据结构也是不可变的。

如果你想确保字典没有变异,你可以使用IReadOnlyDictionary,但鉴于你使用的是匿名类型,你不应该使用这个字典超出了当前方法的范围;鉴于此,你真的不需要这么长时间来防止字典的变异,因为你是唯一应该能够改变字典的人。

答案 1 :(得分:1)

  

如果我变异taskInfoDic,是否可以更改actvProject值(由actvProject对象的成员组成)?

不,因为您提取的所有成员都是值类型。如果有任何引用类型,那么你所拥有的只是一个引用,对基础实例的更改将反映在查询结果中。

  

匿名类型值不应该是不可变的吗?

是的,他们应该,而且他们 。但是,您正在创建词典,其中匿名类型是。字典是可变的,但值(在这种情况下)不是。

答案 2 :(得分:0)

这是一个粗略的例子,显示一旦填充了匿名类型,它的数据就无法隐式更改:

using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
    static void Main(string[] args)
    {
        var actvProject = new Project();

        var taskInfoDic = actvProject.Tasks.Cast<Task>().Select(
        task => new
        {
            task.Guid,
            task.Name
        }).ToDictionary(x => x.Guid);

        actvProject.Tasks[0].Name = "New Task";

        foreach (var t in taskInfoDic)
        {
            Console.WriteLine(t.Value.Name);    // Still "Task 1"
        }

        // This won't compile as "Name" is readonly.
        // taskInfoDic.ElementAt(0).Value.Name = "test";
    }
}

public class Project
{
    public Project()
    {
        Tasks = new List<Task> { new Task { Name = "Task 1" } };
    }

    public IList<Task> Tasks { get; set; }
}

public class Task
{
    public Guid Guid { get; set; }

    public string Name { get; set; }
}