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 来指定查询谓词,同时针对动态列表执行这些谓词。
提前感谢您提供的任何答案或想法。
问候
克雷格
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);
}
}