我希望能够将代码存储在数据库中,然后动态执行它(使用Roslyn)。但是,我希望能够从调用代码中注入(注入?)属性。见下文:
using Roslyn.Scripting.CSharp;
using RoslynMVCTest.Interfaces;
namespace RoslynMVCTest.Services
{
public class MyService
{
private readonly IInjectedService _injectedService;
public MyService(IInjectedService injectedService)
{
_injectedService = injectedService;
}
public bool SomeMethod()
{
string codeString = @"
using RoslynMVCTest.Interfaces;
public class SomethingDoer
{
public IInjectedService InjectedService {get;set;}
public static bool DoSomething()
{
return IInjectedService.SomeOtherMethod();
}
}";
var engine = new ScriptEngine();
var session = engine.CreateSession(_injectedService);
session.AddReference(this.GetType().Assembly);
//How do I set the property in my dynamic code to _injectedService??
var result = session.Execute<bool>("SomethingDoer.DoSomething()");
return result;
}
}
}
我意识到这里可能存在语法和其他问题,但它很好地代表了我想要做的事情。有没有办法做到这一点?
答案 0 :(得分:2)
首先,我将尽可能地回答与原始代码相符的问题。其次,我将展示一个更为简洁的例子,事实上可能就是你所追求的一切。
你可以肯定地声明你的类型,但是必须修复一些事情才能使它变得有意义。
尽管您尝试在静态方法中使用该属性,但您的SomethingDoer
类声明了非静态InjectedService
属性。为了讨论起见,我会假设您打算SomethingDoer.DoSomething
也是非静态的,因此会使该类实现。
public static bool DoSomething()
要:
public bool DoSomething()
您传递给CreateSession
的“sesion”是您的实际服务。要理解为什么这不起作用,你必须理解你传递给CreateSession
的论证意味着什么,以及它做了什么。 “会话”的含义是,该对象的所有公共属性都可作为原始标识符用于脚本会话,而无需.
在任何目标上引用它们。因此,为了使代码正常工作,我引入了一个名为Session
的新类(为方便起见,主要服务类内部):
public class Session
{
public IInjectedService InjectedService { get; set; }
}
此外,我在调用CreateSession
时使用了这个新类:
var session = engine.CreateSession(new Session { InjectedService = _injectedService });
这意味着您InjectedService
内可以使用codeString
属性。
也许最重要的是,您的代码codeString
实际上从未被代码消耗过!您可以理解,您可以将此过程视为为代码设置字符串,然后想象您可以在其中调用一些任意方法。相反,只有一个代码块。因此,如果确实想要在脚本代码中声明一个完整的类,那么仍然必须直接消费脚本代码也是如此。这意味着codeString
的最后两行应该看起来像:
var somethingDoer = new SomethingDoer { InjectedService = InjectedService };
somethingDoer.DoSomething()";
这里我们实例化 SomethingDoer
(因为更改1.)并通过会话提供的隐式InjectedService
值设置服务属性(因为更改2) )。
为了完整起见,这里是完整的示例代码:
namespace RoslynMVCTest.Interfaces
{
public interface IInjectedService
{
bool SomeOtherMethod();
}
}
namespace RoslynMVCTest.Services
{
using RoslynMVCTest.Interfaces;
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new MyService(new InjectedService()).SomeMethod());
Console.ReadLine();
}
}
class InjectedService : IInjectedService
{
public bool SomeOtherMethod()
{
return true;
}
}
public class MyService
{
private readonly IInjectedService _injectedService;
public MyService(IInjectedService injectedService)
{
_injectedService = injectedService;
}
public class Session
{
public IInjectedService InjectedService { get; set; }
}
public bool SomeMethod()
{
string codeString = @"
using RoslynMVCTest.Interfaces;
public class SomethingDoer
{
public IInjectedService InjectedService { get; set; }
public bool DoSomething()
{
return InjectedService.SomeOtherMethod();
}
}
var somethingDoer = new SomethingDoer { InjectedService = InjectedService };
somethingDoer.DoSomething()";
var engine = new ScriptEngine();
var session = engine.CreateSession(new Session { InjectedService = _injectedService });
session.AddReference(this.GetType().Assembly);
//How do I set the property in my dynamic code to _injectedService??
var result = session.Execute<bool>(codeString);
return result;
}
}
}
如果您只想让脚本运行一些与您的服务交互的代码,那么您可以看到,鉴于上述所有要点,这实际上是多么微不足道。因此,为了简明扼要地表达原始代码的意图,您所要做的就是:
var result = session.Execute<bool>("InjectedService.SomeOtherMethod()");
这里传递的代码只是冗长的第一个例子中服务方法的主体。很可能这就是你需要或想要的一切。