C#泛型方法创建Binding实例报CS0417错误,如何实现该需求?
报错原因
C# 泛型的 new() 约束仅支持无参数构造函数的调用,即便你限定了 T 继承自 System.ServiceModel.Channels.Binding 类型,也无法直接通过 new T(参数) 的语法调用带参构造函数,这是C#泛型的固有语法限制,和具体类型是否存在对应带参构造无关。
可行实现方案
方案1:反射调用带参构造(无需改动方法签名)
直接通过反射获取T的string参数构造函数执行,和你原有逻辑完全兼容:
public static T NewBinding2<T>(string pCfgName, string pCfgSuffix, string pAddr) where T : System.ServiceModel.Channels.Binding, new() { T result = null; // 当pCfgSuffix不为空时,优先尝试带后缀的配置名 string cfgId = (!string.IsNullOrEmpty(pCfgSuffix) ? StrUtils.IncludeTrailing(pCfgName, ".") + pCfgSuffix : pCfgName); // 尝试根据配置名创建Binding实例 try { // 反射调用带string参数的构造函数 var ctor = typeof(T).GetConstructor(new[] { typeof(string) }); if (ctor != null) { result = (T)ctor.Invoke(new object[] { cfgId }); } } catch (Exception ex1) { Trace.WriteLine(TrcLvl.TraceError, TrcLvl.TraceError ? string.Format("NewBinding<{0}>.1[{1}]({2}).ERR:{3}\nat {4}", typeof(T), cfgId, pAddr, ErrorUtils.FormatErrorMsg(ex1), ErrorUtils.FormatStackTrace(ex1)) : ""); // 如果带后缀的创建失败,尝试不带后缀的配置名 if (!string.IsNullOrEmpty(pCfgSuffix)) { cfgId = pCfgName; try { var ctor = typeof(T).GetConstructor(new[] { typeof(string) }); if (ctor != null) { result = (T)ctor.Invoke(new object[] { cfgId }); } } catch (Exception ex2) { Trace.WriteLine(TrcLvl.TraceError, TrcLvl.TraceError ? string.Format("NewBinding<{0}>.2[{1}]({2}).ERR:{3}\nat {4}", typeof(T), cfgId, pAddr, ErrorUtils.FormatErrorMsg(ex2), ErrorUtils.FormatStackTrace(ex2)) : ""); } } if (result == null) { // 所有配置读取失败时,使用默认构造函数创建实例,手动设置名称 result = new T(); result.Name = cfgId; } } return result; } // 调用方式和原来完全一致 BasicHttpBinding bnd = NewBinding2<BasicHttpBinding>("bndBasicHttp", "ScreensApi", "http://....");
方案2:传入带参构造委托(性能优于反射)
你提到的 Func<string, T> 方案完全可用,内部生成的cfgId直接作为参数调用委托即可:
// 方法签名新增构造委托参数 public static T NewBinding2<T>(string pCfgName, string pCfgSuffix, string pAddr, Func<string, T> ctorFunc) where T : System.ServiceModel.Channels.Binding, new() { T result = null; string cfgId = (!string.IsNullOrEmpty(pCfgSuffix) ? StrUtils.IncludeTrailing(pCfgName, ".") + pCfgSuffix : pCfgName); try { // 直接调用传入的构造委托 result = ctorFunc(cfgId); } catch (Exception ex1) { Trace.WriteLine(TrcLvl.TraceError, TrcLvl.TraceError ? string.Format("NewBinding<{0}>.1[{1}]({2}).ERR:{3}\nat {4}", typeof(T), cfgId, pAddr, ErrorUtils.FormatErrorMsg(ex1), ErrorUtils.FormatStackTrace(ex1)) : ""); if (!string.IsNullOrEmpty(pCfgSuffix)) { cfgId = pCfgName; try { result = ctorFunc(cfgId); } catch (Exception ex2) { Trace.WriteLine(TrcLvl.TraceError, TrcLvl.TraceError ? string.Format("NewBinding<{0}>.2[{1}]({2}).ERR:{3}\nat {4}", typeof(T), cfgId, pAddr, ErrorUtils.FormatErrorMsg(ex2), ErrorUtils.FormatStackTrace(ex2)) : ""); } } if (result == null) { result = new T(); result.Name = cfgId; } } return result; } // 调用时传入对应类型的带参构造函数即可 BasicHttpBinding bnd = NewBinding2<BasicHttpBinding>("bndBasicHttp", "ScreensApi", "http://....", cfg => new BasicHttpBinding(cfg));
内容的提问来源于stack exchange,提问作者dmitry_bond
相关产品推荐
相关产品推荐

