如何创建含预定义值的参数表达式用于Func<EndpointAddress>
解决方案:绑定预定义参数到Func表达式树
核心思路
你需要创建的是无参数的Func(Of EndpointAddress)(C#为Func<EndpointAddress>),内部已预绑定固定的URL参数值,直接调用目标方法返回结果。不需要保留原ParameterExpression,而是用常量表达式替代外部传入的参数,将URL值硬编码到Func的逻辑中。
VB.NET 实现示例
1. 单个服务的表达式构建
假设你要为DnaServiceClient绑定固定URL:
' 1. 获取目标方法的MethodInfo Dim urlManager = SessionManager.Instance.URLManager Dim targetMethod = urlManager.GetType().GetMethod("DnaService", {GetType(String)}) ' 2. 定义预绑定的URL常量 Dim fixedUrl = "services/DnaService.svc" Dim urlConstant = Expression.Constant(fixedUrl, GetType(String)) ' 3. 创建调用目标方法的表达式(传入url常量) Dim instanceExpr = Expression.Constant(urlManager) Dim callExpr = Expression.Call(instanceExpr, targetMethod, urlConstant) ' 4. 编译为无参数Func(Of EndpointAddress) Dim endpointFunc = Expression.Lambda(Of Func(Of EndpointAddress))(callExpr).Compile() ' 5. 添加到字典 _endpointLookup.Add(GetType(DnaService.DnaServiceClient), endpointFunc)
2. 通用化封装(适配所有服务)
可以写一个通用方法批量生成,减少重复代码:
Private Function CreateEndpointFunc(Of TClient)(urlManager As URLManager, methodName As String, fixedUrl As String) As Func(Of EndpointAddress) Dim targetMethod = urlManager.GetType().GetMethod(methodName, {GetType(String)}) If targetMethod Is Nothing Then Throw New ArgumentException($"Method {methodName} not found on URLManager") End If Dim urlConstant = Expression.Constant(fixedUrl, GetType(String)) Dim instanceExpr = Expression.Constant(urlManager) Dim callExpr = Expression.Call(instanceExpr, targetMethod, urlConstant) Return Expression.Lambda(Of Func(Of EndpointAddress))(callExpr).Compile() End Function ' 使用示例 _endpointLookup.Add(GetType(DnaService.DnaServiceClient), CreateEndpointFunc(Of DnaServiceClient)(SessionManager.Instance.URLManager, "DnaService", "services/DnaService.svc")) _endpointLookup.Add(GetType(VinService.VinServiceClient), CreateEndpointFunc(Of VinServiceClient)(SessionManager.Instance.URLManager, "VinService", "services/VinService.svc"))
C# 实现示例
1. 单个服务的表达式构建
// 1. 获取目标方法的MethodInfo var urlManager = SessionManager.Instance.URLManager; var targetMethod = urlManager.GetType().GetMethod("DnaService", new[] { typeof(string) }); // 2. 定义预绑定的URL常量 var fixedUrl = "services/DnaService.svc"; var urlConstant = Expression.Constant(fixedUrl, typeof(string)); // 3. 创建调用目标方法的表达式 var instanceExpr = Expression.Constant(urlManager); var callExpr = Expression.Call(instanceExpr, targetMethod, urlConstant); // 4. 编译为无参数Func<EndpointAddress> var endpointFunc = Expression.Lambda<Func<EndpointAddress>>(callExpr).Compile(); // 5. 添加到字典 _endpointLookup.Add(typeof(DnaService.DnaServiceClient), endpointFunc);
2. 通用化封装
private Func<EndpointAddress> CreateEndpointFunc<TClient>(URLManager urlManager, string methodName, string fixedUrl) { var targetMethod = urlManager.GetType().GetMethod(methodName, new[] { typeof(string) }); if (targetMethod == null) throw new ArgumentException($"Method {methodName} not found on URLManager"); var urlConstant = Expression.Constant(fixedUrl, typeof(string)); var instanceExpr = Expression.Constant(urlManager); var callExpr = Expression.Call(instanceExpr, targetMethod, urlConstant); return Expression.Lambda<Func<EndpointAddress>>(callExpr).Compile(); } // 使用示例 _endpointLookup.Add(typeof(DnaService.DnaServiceClient), CreateEndpointFunc<DnaServiceClient>(SessionManager.Instance.URLManager, "DnaService", "services/DnaService.svc")); _endpointLookup.Add(typeof(VinService.VinServiceClient), CreateEndpointFunc<VinServiceClient>(SessionManager.Instance.URLManager, "VinService", "services/VinService.svc"));
适配原有ServiceController的扩展
如果你要替换原有的ServiceController逻辑,可以结合这个字典实现自动初始化客户端:
// C# 示例:简化的Service替代类 public class ServiceInvoker { private readonly Dictionary<Type, Func<EndpointAddress>> _endpointLookup; public ServiceInvoker(Dictionary<Type, Func<EndpointAddress>> endpointLookup) { _endpointLookup = endpointLookup; } public TResult Invoke<TService, TClient>(Func<TService, TResult> operation) where TClient : ClientBase<TService>, TService, new() { if (!_endpointLookup.TryGetValue(typeof(TClient), out var endpointFunc)) throw new InvalidOperationException($"No endpoint configured for {typeof(TClient).Name}"); using var client = new TClient(endpointFunc()); return operation(client); } } // 调用方式(和原有代码兼容) var invoker = new ServiceInvoker(_endpointLookup); var result = invoker.Invoke<IVinService, VinServiceClient>(vinService => vinService.DecodeVin(vehicleIdentificationNumber));
内容的提问来源于stack exchange,提问作者Patrick Shaffer -State Police-
相关产品推荐
相关产品推荐

