C# 表达式序列化/参数替换

本文关键字:参数 替换 序列化 表达式 | 更新日期: 2023-09-27 18:33:59

首先,简要概述一下我要做的事情:我想获取一个 C# 表达式,对其进行序列化,将其发送到另一个进程,对其进行反序列化,并使用它来筛选列表。 这里有一个警告 - 当创建表达式时,它是针对泛型参数类型 T 完成的,但是当它被反序列化时,它需要反对动态。 这样做的原因是,当它最终在不同的进程中在服务器上使用时,它将针对动态列表完成,因为我在该上下文中没有类型信息。

我觉得我已经很接近了,因为我已经使用了Newtonsoft.Json和Serialize.Linq库来组合概念证明,但我只能在不使用动态的情况下让它工作(例如,我在序列化端(客户端(和反序列化端(服务器(都有可用的T类型。 使用一些代码向您展示我所拥有的...

鉴于此:

public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
}

。作为我们正在处理的类型。 我有一个具有接口的客户端:

public interface IClient
{
    T Get<T>(Expression<Func<T, bool>> query);
}

。这样我就可以这样做:

var client = new Client();
var john = client.Get<Person>(p => p.Name == "John");

。到目前为止,一切都很好。 在客户端中。Get(( 方法 我正在获取传递的表达式并将其序列化并发送到服务器。 服务器如下所示:

 public dynamic Server(string serializedExpression)
 {
    var people = new List<dynamic>
    {
        new { Name = "John", Email = "john@stackoverflow.com" },
        new { Name = "Jane", Email = "jane@stackoverflow.com" }
    };
    var serializer = new ExpressionSerializer(new JsonSerializer());
    var deserializedExpression = (Expression<Func<dynamic, bool>>)serializer.DeserializeText(serializedExpression);
    return people.FirstOrDefault(deserializedExpression.Compile());
}

。这就是问题发生的地方,因为我试图将其反序列化为一种

Expression<Func<dynamic, bool>> 

。而不是。。。

Expression<Func<Person, bool>>.

所以我的问题是:

1(我正在尝试做的事情甚至可能吗? 似乎使用 ExpressionVisitor 您可以更改通用参数类型,我尝试这样做以在序列化和发送之前从 Person 更改为动态,但没有运气。

2(有没有更好的方法来做我想完成的事情? 我知道第一个问题是为什么我不在服务器上访问表达式 Func <> 中指定的类型 T,但由于服务器的性质,这是不可能的。 我基本上希望在客户端上使用 Linq 来指定查询谓词,同时针对动态列表执行这些谓词。

提前感谢您提供的任何答案或想法。

问候

克雷格

C# 表达式序列化/参数替换

LINQ 不太喜欢表达式中的动态。(也许是DLINQ?

或者,您可以向服务器传递有关您正在使用的对象类型的提示。我意识到这可能不是您要找的,但它正在起作用:

(借自这篇代码项目文章(

public static class Extensions
{
    public static object ToType<T>(this object obj, T type)
    {
        //create instance of T type object:
        var tmp = Activator.CreateInstance(Type.GetType(type.ToString()));
        //loop through the properties of the object you want to covert:          
        foreach (PropertyInfo pi in obj.GetType().GetProperties())
        {
            try
            {
                //get the value of property and try 
                //to assign it to the property of T type object:
                tmp.GetType().GetProperty(pi.Name).SetValue(tmp,
                                          pi.GetValue(obj, null), null);
            }
            catch { }
        }
        //return the T type object:         
        return tmp;
    }
    public static object ToNonAnonymousList<T>(this List<T> list, Type t)
    {
        //define system Type representing List of objects of T type:
        var genericType = typeof(List<>).MakeGenericType(t);
        //create an object instance of defined type:
        var l = Activator.CreateInstance(genericType);
        //get method Add from from the list:
        MethodInfo addMethod = l.GetType().GetMethod("Add");
        //loop through the calling list:
        foreach (T item in list)
        {
            //convert each object of the list into T object 
            //by calling extension ToType<T>()
            //Add this object to newly created list:
            addMethod.Invoke(l, new object[] { item.ToType(t) });
        }
        //return List of T objects:
        return l;
    }
}

。在服务器上有一些不太好的分支:

public interface IClient
{
    T Get<T>(Expression<Func<T, bool>> query);
}
public class Person
{
    public string Name { get; set; }
    public string Email { get; set; }
}
public class Client
{
    public T Get<T>(Expression<Func<dynamic, bool>> query)
    {
        var serializer = new ExpressionSerializer(new JsonSerializer());
        var serializedExpression = serializer.SerializeText(query);
        return (T)Server.Retrieve(serializedExpression, typeof(T).FullName);
    }
}
public static class Server
{
    public static dynamic Retrieve(string serializedExpression, string targetType)
    {
        var people = new List<dynamic> 
            {
                new { Name = "John", Email = "john@stackoverflow.com" },
                new { Name = "Jane", Email = "jane@stackoverflow.com" }
            };
        // Try creating an object of the type hint passed to the server
        var typeInstance = Activator.CreateInstance(Type.GetType(targetType));
        if (typeInstance.GetType() == typeof(Person))
        {
            var serializer = new ExpressionSerializer(new JsonSerializer());
            var deserializedExpression = (Expression<Func<Person, bool>>)serializer.DeserializeText(serializedExpression);
            var peopleCasted = (IEnumerable<Person>)people.ToNonAnonymousList(typeof(Person));
            return peopleCasted.Where(deserializedExpression.Compile()).SingleOrDefault();
        }
        else
        {
            throw new ArgumentException("Type is unknown");
        }
    }
}

和工作测试:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void MyTestMethod()
    {
        var client = new Client();
        var john = client.Get<Person>(p => p.Name == "John");
        Assert.IsNotNull(john);
    }
}