Roslyn C#CSharpCompilation-动态编译

JDC

Roslyn编译器和动力学->我正在尝试编译仅在运行时才知道的属性。
该代码在Visual Studio中编译时有效。使用Roslyn进行编译时,动态属性为“未知”。

在此示例单元测试中,我有一个继承自DynamicObject的MyObject。这些属性随简单的KeyValue字典一起提供。

当以硬编码方式使用“ MyObject”时,我可以调用属性Hello。我实际上可以在编译时使用任何属性。不存在的属性在运行时会出错。(预期行为)

在传递给roslyn编译器的代码中使用“ MyObject”时,我无法在动态对象上使用任何属性。在这里,属性“ Hello”给我错误:

CS1061 - 'MyObject' does not contain a definition for 'Hello' and no accessible extension method 'Hello' accepting a first argument of type 'MyObject' could be found (are you missing a using directive or an assembly reference?)

我想念什么?

单元测试示例:

using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Testing {
    [TestClass]
    public class FullExampleTest {
        [TestMethod]
        public void HardCoded() {
            var map = new Dictionary<string, string>() {
                { "Hello","Foo"},
                { "World","Bar"}
            };
            dynamic src = new MyObject(map);
            Console.WriteLine(src.Hello);

            Assert.AreEqual("Foo Bar", $"{src.Hello} {src.World}");
        }

        [TestMethod]
        public void CompileAtRuntime() {
            string code = @"
                using System;
                using System.Collections.Generic;
                using System.Diagnostics.Contracts;
                using System.Dynamic;
                using System.IO;
                using System.Linq;
                using System.Reflection;
                using Testing;

                namespace MyNamespace{{
                    public class MyClass{{
                        public static void MyMethod(MyObject src){{
                            Console.WriteLine(src.Hello);
                        }}
                    }}
                }}
           ";

            var ns = Assembly.Load("netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51");

            MetadataReference[] references = new MetadataReference[]
            {
                MetadataReference.CreateFromFile(ns.Location), //netstandard
                MetadataReference.CreateFromFile(typeof(Object).Assembly.Location), //mscorlib
                MetadataReference.CreateFromFile(typeof(DynamicObject).Assembly.Location), //System.Core
                MetadataReference.CreateFromFile(typeof(RuntimeBinderException).Assembly.Location),//Microsoft.CSharp
                MetadataReference.CreateFromFile(typeof(Action).Assembly.Location), //System.Runtime
                MetadataReference.CreateFromFile(typeof(FullExampleTest).Assembly.Location) // this assembly
            };


            var comp = CSharpCompilation.Create(
                assemblyName: Path.GetRandomFileName(),
                syntaxTrees: new[] { CSharpSyntaxTree.ParseText(code) },
                references: references,
                options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
            );

            using (var ms = new MemoryStream()) {
                var result = comp.Emit(ms);
                if (!result.Success) {
                    var failures = result.Diagnostics.Where(diagnostic => diagnostic.IsWarningAsError || diagnostic.Severity == DiagnosticSeverity.Error);

                    foreach (Diagnostic diagnostic in failures) {
                        Console.WriteLine($"{diagnostic.Id} - {diagnostic.GetMessage()}");
                    }
                }
                Assert.IsTrue(result.Success, "Compilation failure..");
            }
        }
    }

    public class MyObject : DynamicObject {
        private IDictionary<string, string> _Map;

        public MyObject(IDictionary<string, string> map) {
            _Map = map;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result) {
            Contract.Assert(binder != null);

            var ret = _Map.TryGetValue(binder.Name, out string value);
            result = value;
            return ret;
        }

        public override bool TryInvokeMember(InvokeMemberBinder binder,     object[] args, out object result) {
            Contract.Assert(binder != null);

            var ret = _Map.TryGetValue(binder.Name, out string value);
            result = value;
            return ret;
        }

    }
}
脱衣战士

您的动态编译代码与静态编译的代码不同。在动态编译的代码中,您已明确声明srcdynamic您的“硬编码”示例尝试将其视为MyObject如果您的硬编码测试如下所示,您将遇到相同的问题:

    var src = new MyObject(map);
    Console.WriteLine(src.Hello);

因此,您可以通过将srcas强制转换dynamic

public static void MyMethod(MyObject src){
    Console.WriteLine(((dynamic)src).Hello);
}

或者首先将其声明为动态的:

public static void MyMethod(dynamic src){
    Console.WriteLine(src.Hello);
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

C#Roslyn .NET CORE 3.1 CSharpCompilation动态RuntimeBinder.Binder.Convert错误

ASP.NET 5 Roslyn动态编译

Roslyn无法编译代码

如何使用Roslyn以编程方式编译C#文件?

Roslyn C#编译器如何启动?

在roslyn中解析C#条件编译语句

使用Roslyn编译语法树

是否可以使用.NET Core Roslyn编译器编译单个C#代码文件?

如何在Roslyn动态编译的代码中引用另一个DLL

在NetStandard2.0项目中使用Roslyn编译动态创建的代码

Roslyn-CodeDom:如何将代码动态编译为Universal-Windows-Library

行号不包含在异常Stacktrace中(用Roslyn动态编译的代码)

Visual Studio 2015 / C#6 / Roslyn无法在PCL项目中编译XML注释

使用.Net编译器Roslyn为C#代码创建控制流程图

使用Roslyn(csc.exe)定位.NET 3.5时手动编译C#

如何在Visual Studio 2015中使用roslyn C#编译器?

C#Roslyn编译器-如何从IdentifierNameSyntax获取类型的名称空间?

`.NET Compiler Platform SDK` & `C# 和 Visual Basic Roslyn 编译器` 之间的区别

使用Roslyn CSharpCompilation生成.NET Standard 2.0 DLL

Roslyn编译的嵌入式文件

Roslyn是完整的编译器吗?

在Visual Studio中使用自编译的Roslyn?

无法从源代码在Roslyn中创建编译

使用roslyn进行编译和即时修改

Roslyn编译失败,但与Visual Studio兼容

使用Roslyn API编译.NET Core App

如何调试从Roslyn编译生成的dll?

如何进行Roslyn编译以复制引用

Roslyn-动态(运行时)流程