目标v4.0时对v4.5类的不明确引用

时间:2016-04-18 13:14:27

标签: c# .net

我的办公室目前使用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 Studio中编译它,没有编译错误。脚本相当大,但这是一个简单的例子,我能够重现这个问题。首先,我使用默认实现在自己的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 framework 4,并且构建没有错误。但是,以调试模式运行程序会创建此输出:

编译失败!错误计数:1 'ReadOnlyDictionary'是'System.Collections.ObjectModel.ReadOnlyDictionary'和'TestReadOnlyDictionary.ReadOnlyDictionary'

之间的模糊引用

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

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

您的问题是您希望将.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并加载生成的程序集)。