繁体   English   中英

以 v4.0 为目标时对 v4.5 的模糊引用 class

[英]Ambiguous reference to v4.5 class when targetting v4.0

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

“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,并且构建没有错误。 然而,在调试模式下运行程序会创建这个 output:

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

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

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

您的问题是,您要针对.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并加载生成的程序集)不同。

我在 Azure DevOps 上遇到这样的错误:

error CS0104: 'IDisposable' is an ambiguous reference between 'System.IDisposable' and 'System.IDisposable'

奇怪的错误,因为它只是间歇性地发生并且使用 Azure 虚拟机规模集代理。 从不在本地主机上。

在受影响的文件中Remove and Sort Usings in Visual Studio 以及从System.IDisposable而不是IDisposable继承。

https://learn.microsoft.com/en-us/do.net/csharp/misc/cs0104

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM