Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将字符串解析为C#lambda Func_C#_Linq - Fatal编程技术网

将字符串解析为C#lambda Func

将字符串解析为C#lambda Func,c#,linq,C#,Linq,有没有办法将lambda的字符串表示形式转换为lambda Func Func<Product, bool> func = Parse<Product, bool>("product => product.Name.Length > 0"); 因此,作为一种解决方法,我希望将lambda作为字符串传递:“role=>role.CanDoThis&&role.AllowedCount>5”。但似乎我必须像这样使用DLINQ:“CanDoThis&&Allowe

有没有办法将lambda的字符串表示形式转换为lambda Func

Func<Product, bool> func = Parse<Product, bool>("product => product.Name.Length > 0");

因此,作为一种解决方法,我希望将lambda作为字符串传递:“role=>role.CanDoThis&&role.AllowedCount>5”。但似乎我必须像这样使用DLINQ:“CanDoThis&&AllowedCount>5”-因为这是它理解的语法。但我的问题是关于真正的lambdas,我在提问时已经使用了DLINQ。

您可以解析字符串并使用该类构建lambda表达式,本质上复制编译器的功能。

您可以使用(用更多代码包装表达式,以创建有效类并将其编译成程序集,然后加载程序集)


我相信这就是原因。

我想您必须求助于CSharpCodeProvider。但是,处理所有可能的局部变量引用可能不是一件小事。您将如何告诉CSharpCodeProvider lambda参数的类型?我可能会创建一个如下所示的模板类:

class ExpressionContainer {
    public Expression<Func<Product, bool>> TheExpression;
    public string Length;

    public ExpressionContainer() {
        TheExpression = <user expression text>;
    }
}
string source = <Code from above>;
Assembly a;
using (CSharpCodeProvider provider = new CSharpCodeProvider(...) {
    List<string> assemblies = new List<string>();
    foreach (Assembly x in AppDomain.CurrentDomain.GetAssemblies()) {
        try {
            assemblies.Add(x.Location);
        }
        catch (NotSupportedException) {
            // Dynamic assemblies will throw, and in .net 3.5 there seems to be no way of finding out whether the assembly is dynamic before trying.
        }
    }

    CompilerResults r = provider.CompileAssemblyFromSource(new CompilerParameters(assemblies.ToArray()) { GenerateExecutable = false, GenerateInMemory = true }, source);
    if (r.Errors.HasErrors)
        throw new Exception("Errors compiling expression: " + string.Join(Environment.NewLine, r.Errors.OfType<CompilerError>().Select(e => e.ErrorText).ToArray()));
    a = r.CompiledAssembly;
}
object o = a.CreateInstance("ExpressionContainer");
var result = ( Expression<Func<Product, bool>>)o.GetType().GetProperty("TheExpression").GetValue(o);
class ExpressionContainer{
公开表达;
公共字符串长度;
public ExpressionContainer(){
表达式=;
}
}
然后像这样做:

class ExpressionContainer {
    public Expression<Func<Product, bool>> TheExpression;
    public string Length;

    public ExpressionContainer() {
        TheExpression = <user expression text>;
    }
}
string source = <Code from above>;
Assembly a;
using (CSharpCodeProvider provider = new CSharpCodeProvider(...) {
    List<string> assemblies = new List<string>();
    foreach (Assembly x in AppDomain.CurrentDomain.GetAssemblies()) {
        try {
            assemblies.Add(x.Location);
        }
        catch (NotSupportedException) {
            // Dynamic assemblies will throw, and in .net 3.5 there seems to be no way of finding out whether the assembly is dynamic before trying.
        }
    }

    CompilerResults r = provider.CompileAssemblyFromSource(new CompilerParameters(assemblies.ToArray()) { GenerateExecutable = false, GenerateInMemory = true }, source);
    if (r.Errors.HasErrors)
        throw new Exception("Errors compiling expression: " + string.Join(Environment.NewLine, r.Errors.OfType<CompilerError>().Select(e => e.ErrorText).ToArray()));
    a = r.CompiledAssembly;
}
object o = a.CreateInstance("ExpressionContainer");
var result = ( Expression<Func<Product, bool>>)o.GetType().GetProperty("TheExpression").GetValue(o);
字符串源=;
大会a;
使用(CSharpCodeProvider provider=新的CSharpCodeProvider(…){
列表程序集=新列表();
foreach(AppDomain.CurrentDomain.GetAssemblys()中的程序集x){
试一试{
组件。添加(x.位置);
}
捕获(不支持异常){
//动态程序集将抛出,在.NET3.5中,在尝试之前似乎无法确定程序集是否是动态的。
}
}
CompilerResults r=provider.CompileAsemblyFromSource(新编译器参数(assemblies.ToArray()){GenerateExecutable=false,GenerateInMemory=true},source);
if(r.Errors.hasrerrors)
抛出新异常(“编译表达式时出错:”+string.Join(Environment.NewLine,r.Errors.OfType().Select(e=>e.ErrorText.ToArray());
a=r.编译组件;
}
对象o=a.CreateInstance(“ExpressionContainer”);
var result=(表达式)o.GetType().GetProperty(“表达式”).GetValue(o);

但是,请注意,对于长时间运行的应用程序,您应该在单独的appdomain中创建所有这些内存中的程序集,因为只有卸载它们所在的appdomain才能释放它们。

它们有许多可用的lambda表达式解析器。其中一些是

示例代码:

示例1:字符串concat和数字计算:

string code = "2.ToString()+(4*2)"; // C# code Func<string> 
func = ExpressionParser.Compile<Func<string>>(code); // compile code 
string result = func(); // result = "28"
string code=“2.ToString()+(4*2)”;//C#code Func
func=ExpressionParser.Compile(code);//编译代码
字符串result=func();//result=“28”

针对您更具体的问题,(您可能已经知道这一点,但我还是会尝试提及),您可以创建一个字典,将常量值(整数或枚举)映射到lambda

sealed class Product {
   public bool CanDoThis { get; set; }
   public int AllowedCount { get; set; }
}

public enum SecureFuncType {
   Type1,
   Type2,
   Type3
}

sealed class SecureAttribute : Attribute {
   [NotNull] readonly Func<Product, bool> mFunc;

   public SecureAttribute(SecureFuncType pType) {
      var secureFuncs = new Dictionary<SecureFuncType, Func<Product, bool>> {
         { SecureFuncType.Type1, role => role.CanDoThis && role.AllowedCount > 1 },
         { SecureFuncType.Type2, role => role.CanDoThis && role.AllowedCount > 2 },
         { SecureFuncType.Type3, role => role.CanDoThis && role.AllowedCount > 3 }
      };

      mFunc = secureFuncs[pType];
   }
}

我知道如何调用csc.exe,并且有使用CodeDom进行动态编译的经验,这太多开销了-根据我的经验,它实际上运行csc.exe(当我在.NET 1.1上使用它时)。我想花时间在它上可能会很有趣,但对我的客户来说不是这样的-他们不付我钱来编写C#编译器。多么奇怪的客户啊。:)你为什么担心启动编译器会很慢?你可以缓存生成的表达式。看起来C#5会带来一些你想要的东西。看一看PDC 2008的视频,Anders Hejlsberg在视频中谈到了C#的未来。我正在等待C#4.0发布……C#5离我们太远了;-)实际上,我需要在属性中为lambdas提供此功能。希望4.0会有它(以及通用属性)。在c#4.0中不会有通用属性。遗憾的是,对于这种情况,我需要能够将lambda/delegate传递给属性,而不是泛型属性。参考问题中的4.0规范让我感到害怕;-)它甚至不包含“lambda”这个词!是的,然后我会让csc.exe运行,AppDomains只运行几个lambda。。。这让我想起了我的Turbo Pascal程序,它允许用户输入表达式。。。并且必须与Turbo Pascal编译器一起部署;-)另一方面,有一种叫做“动态方法”的方法。这是一种更轻量级的处理此类情况的方法。不幸的是,我从未使用过它们/@女王:这有关系吗?您的客户已经部署了csc,因为它是框架的一部分。另外,在单独的appdomain中运行的全部目的是,您可以检索值,然后拆下appdomain。您的客户可以购买相当多的新服务器来处理计算,而不用自己实现编译器,这样可以节省成本。