【问题标题】:Ambiguous reference to v4.5 class when targetting v4.0以 v4.0 为目标时对 v4.5 类的模糊引用
【发布时间】:2016-04-18 13:14:27
【问题描述】:

我的办公室目前使用 VS 2010/.NET 4.0。我们实现了我们自己的通用版本的 ReadOnlyDictionary,我相信它直到 4.5 才本地引入。我们还在一个应用程序中对 C# 脚本进行了一些动态编译和运行。最近,我们创建了一个包含自定义泛型 ReadOnlyDictionary 的 C# 脚本,但是当代码被动态编译时,编译失败:

“ReadOnlyDictionary”是“System.Collections.ObjectModel.ReadOnlyDictionary”和“Utilities.ReadOnlyDictionary”之间的模糊引用

不明确的引用指向“System.Collections.ObjectModel”命名空间,所以我仔细检查了,4.0 中的命名空间似乎不包含 ReadOnlyDictionary 的通用实现。我可以通过使用命名空间限定我们的自定义 ReadOnlyDictionary 来避免脚本失败,但我仍然想知道为什么这是必要的。

我采用相同的 C# 脚本并在 Visual Studios 中编译它,没有编译错误。该脚本相当大,但这是一个简单的示例,我能够重现该问题。首先,我在自己的 DLL/命名空间中创建了 ReadOnlyDictionary 的虚拟版本,并使用默认实现:

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

namespace TestReadOnlyDictionary
{
    public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
    {
        public void Add(TKey key, TValue value)
        {
            throw new NotImplementedException();
        }

        public bool ContainsKey(TKey key)
        {
            throw new NotImplementedException();
        }

        public ICollection<TKey> Keys
        {
            get { throw new NotImplementedException(); }
        }

        public bool Remove(TKey key)
        {
            throw new NotImplementedException();
        }

        public bool TryGetValue(TKey key, out TValue value)
        {
            throw new NotImplementedException();
        }

        public ICollection<TValue> Values
        {
            get { throw new NotImplementedException(); }
        }

        public TValue this[TKey key]
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void Add(KeyValuePair<TKey, TValue> item)
        {
            throw new NotImplementedException();
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public bool Contains(KeyValuePair<TKey, TValue> item)
        {
            throw new NotImplementedException();
        }

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsReadOnly
        {
            get { throw new NotImplementedException(); }
        }

        public bool Remove(KeyValuePair<TKey, TValue> item)
        {
            throw new NotImplementedException();
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            throw new NotImplementedException();
        }
    }
}

然后我编写了一个简单的控制台应用程序,其中包含这个虚拟 ReadOnlyDictionary 的一个实例,并尝试编译它自己的源代码:

using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.Text;

using TestReadOnlyDictionary;

namespace TestCompile
{
    class Program
    {
        ReadOnlyDictionary<string, string> _dictionary = new ReadOnlyDictionary<string, string>();

        private static void Main(string[] args)
        {
            string script = @"..\..\Program.cs";
            string scriptText = File.ReadAllText(script);

            var providerOptions = new Dictionary<string, string>()
            {
                { "CompilerVersion", "v4.0" }
            };
            CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp", providerOptions);

            CompilerParameters parameters = new CompilerParameters();
            parameters.GenerateExecutable = true;
            parameters.GenerateInMemory = true;
            parameters.ReferencedAssemblies.Add("System.dll");
            parameters.ReferencedAssemblies.Add("System.Core.dll");
            parameters.ReferencedAssemblies.Add("System.Data.dll");
            parameters.ReferencedAssemblies.Add(@"..\..\..\ReadOnlyDictionary\bin\Release\ReadOnlyDictionary.dll");

            CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, scriptText);
            if (results.Errors.Count == 0)
                Console.WriteLine("Compile succeeded: " + results.CompiledAssembly.FullName);
            else
            {
                Console.WriteLine("Compile failed! Error count: " + results.Errors.Count);
                foreach (CompilerError error in results.Errors)
                    Console.WriteLine(error.ErrorText);
            }
        }
    }
}

此项目面向 .NET 框架 4,并且构建时没有错误。但是,在调试模式下运行程序会产生以下输出:

编译失败!错误计数:1 'ReadOnlyDictionary' 是 'System.Collections.ObjectModel.ReadOnlyDictionary' 和 'TestReadOnlyDictionary.ReadOnlyDictionary' 之间的模糊引用

4.0 版的这个编译器是否以某种方式引用了 .NET 框架 4.5?还有其他方法可以告诉编译器以框架 4.0 为目标吗?

【问题讨论】:

  • 错误的引用程序集,您不能再使用 c:\windows\microsoft.net 目录中的程序集了。它们必须来自 c:\program files (x86)\reference assembly 目录。
  • 谢谢汉斯,我用“C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\”完全限定了引用,它现在运行成功。您是否有一个链接可以解释参考文献的真实情况?我不确定我是否理解。
  • 谢谢汉斯!我们在工作上有点落后于时代,所以我要赶上最新的框架。

标签: c# .net


【解决方案1】:

我与其他 dll 有类似的问题。我的问题是构建服务器没有 .Net 4.0 目标包,并且正在默默地构建我的 .Net 4.5 版本。检查您的构建输出是否有任何警告或错误。

【讨论】:

  • 好的,有趣:我转储了 CompilerResults 输出,它包含以下内容:Microsoft (R) Visual C# Compiler version 4.0.30319.34209 for Microsoft (R) .NET Framework 4.5 版权所有 (C) Microsoft Corporation。版权所有。现在的问题是如何告诉它以 4.0 为目标?这发生在 VS 2010 中,在我的 PC 上处于调试模式。
【解决方案2】:

你的问题是你想以 .NET 4.0 框架为目标,这与编译器版本无关(例如我可以使用 C# 6 编译一个 .NET 2.0 应用程序就好了)。

现在,4.5 是 4.0 的就地更新。这意味着您的计算机上不再存在 4.0。因此,仅使用 C:\Windows\Microsoft.NET 将不允许您引用正确的程序集 - 您必须明确使用 4.0 的引用程序集 - c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0

作为补充说明,CodeDomProvider 和朋友现在有点过时了。如果您想使用最新的 C# 功能,则必须改用 Roslyn。作为额外的奖励,Roslyn 完全在内存中进行编译,这与 CodeDomProvider 不同(它只运行 csc 并加载生成的程序集)。

【讨论】:

  • 前提是 .Net 2.0 已安装,或者目标包可用
  • @AndreyMarchuk 同样,这与 编译器 无关。编译器并不关心您使用的是什么 DLL - 它们只是 DLL 和其他任何 DLL 一样。清单和其他配置也是如此。
猜你喜欢
  • 2014-02-14
  • 2020-12-20
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多