在迭代

时间:2017-08-15 07:43:26

标签: c# readonly-collection

我有以下属性:

private static Collection<Assembly> _loadedAssemblies = new Collection<Assembly>();
    internal static ReadOnlyCollection<Assembly> LoadedAssemblies
    {
        get { return new ReadOnlyCollection<Assembly>(_loadedAssemblies); }
    }

在另一个课程中,我循环浏览LoadedAssemblies

foreach (Assembly assembly in ResourceLoader.LoadedAssemblies)

循环遍历程序集时,底层集合(_loadedAssemblies)有时会更改System.InvalidOperationException。使LoadedAssemblies安全的首选方法是什么?我无法重现这个问题所以我不能尝试。

可以吗?

internal static ReadOnlyCollection<Assembly> LoadedAssemblies
    {
        get { return new ReadOnlyCollection<Assembly>(_loadedAssemblies.ToList()); }
    }

修改

    public static void Initialize()
    {

        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            AddAssembly(assembly);
        }
        AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.AssemblyLoad += OnAssemblyLoad;
    }

    private static void OnAssemblyLoad(object sender, AssemblyLoadEventArgs args)
    {
        AddAssembly(args.LoadedAssembly);
    }

    private static void AddAssembly(Assembly assembly)
    {
        AssemblyName assemblyName = new AssemblyName(assembly.FullName);
        string moduleName = assemblyName.Name;

        if (!_doesNotEndWith.Exists(x => moduleName.EndsWith(x, StringComparison.OrdinalIgnoreCase)) &&
            _startsWith.Exists(x => moduleName.StartsWith(x, StringComparison.OrdinalIgnoreCase)))
        {
            if (!_loadedAssemblies.Contains(assembly))
            {
                _loadedAssemblies.Add(assembly);
            }
        }
    }

2 个答案:

答案 0 :(得分:3)

ReadOnlyCollection<T>只是原始集合的包装,可以防止直接修改。但是如果将它暴露在某个地方,它不会阻止修改底层集合。

由于ReadOnlyCollection<T>.GetEnumerator只返回基础集合的枚举器,因此它具有相同的规则。枚举时不能修改它,这意味着不允许添加或删除项目。

没有看到你的代码就没有简单的修复方法,防止多个线程同时访问底层集合,例如:使用lock。 如果你在foreach中修改它可能更容易修复,但我们需要看到那些代码。

答案 1 :(得分:3)

您在问题中提出的建议是有效的。那就是:

internal static ReadOnlyCollection<Assembly> LoadedAssemblies
{
    get { return new ReadOnlyCollection<Assembly>(_loadedAssemblies.ToList()); }
}

原因是您的问题来自于_loadedAssemblies在您对其进行枚举时的更改。这当然是因为ReadOnlyCollection只是_loadedAssemblies的包装器,它使用了基本集合的枚举器。

如果您执行_loadedAssemblies.ToList(),则会创建一个新列表,该列表是原始_loadedAssemblies的副本。它在创建时将具有所有相同的元素,但永远不会再次更新(因为您甚至没有对新集合的引用,您无法对其进行修改)。这意味着当_loadedAssemblies更新时,ReadOnlyCollection内的新列表很幸运地没有发现这种变化,因此您的枚举将继续没有问题到最后。