C#泛型约束与策略模式实现问题求助
背景
为消除冗余代码,我采用策略模式,将原冗余代码放入策略模式的上下文类中,该类会调用IsSuccess ProcessApiMethod()方法,上下文类无问题,仅作完整展示。
难点
ProcessApiMethod()方法在TOut为类类型时需返回null,但TOut也可为int、bool等值类型。
已解决部分
- 部分API方法返回类型为void,因此我实现了两个不同接口。
当前问题
- C#是否支持备选泛型约束?
- 如何仅允许值类型作为
T的可用类型?
我期望类似如下的约束写法:
public interface ISuccessConverterStrategy<TOut> where Tout : (class || basicType)
但如下写法无意义:
public interface ISuccessConverterStrategy<TOut> where Tout : (class || (!class && !struct))
若第一个问题答案为“否”,该如何解决?
目前无论如何尝试,策略类编译时均提示“未实现接口成员'TOut SuccessConverter.ISuccessConverterStrategy.GetResult()'”或其他泛型使用问题。
问题解答
C#不支持备选泛型约束
C#泛型约束仅支持交集逻辑,只能同时满足多个约束条件,无法使用||这类“或”逻辑的备选约束。如果你的需求是覆盖所有类型(引用类型+值类型),不需要添加任何约束——泛型参数默认即可接受任意类型。仅允许值类型的泛型约束写法
若要限制T只能是值类型,直接使用struct约束:public interface ISuccessConverterStrategy<TOut> where TOut : struct该约束会排除所有引用类型,仅允许int、bool、自定义结构体等值类型。如果需要支持可空值类型(如
int?),C# 8.0+中可直接搭配TOut?语法实现兼容。
编译错误核心修复
你的代码编译报错的根源是接口方法签名不匹配:ISuccessConverterStrategy<TOut>中的GetResult<TOut>()是泛型方法,但实现类中写的是非泛型GetResult(),两者签名不一致。
正确的接口定义应去掉方法上的泛型参数,复用接口本身的泛型参数:
public interface ISuccessConverterStrategy<TOut> : ISuccessConverterStrategy { /// <summary> /// 获取处理结果: /// - 引用类型:处理失败/无结果时返回null /// - 值类型:处理失败时返回默认值 /// </summary> /// <returns></returns> TOut? GetResult(); // C#8.0+可空语法,兼容引用/值类型的null/默认值返回 }
另外,FuncIntOutStrategy<int>的写法错误,泛型类定义无需在类名后指定具体类型,应改为通用值类型处理类:
public class FuncValueTypeOutStrategy<TOut> : ISuccessConverterStrategy<TOut> where TOut : struct { private Func<TOut> _apiMethod; private TOut _result; public void SetApiMethod(Func<TOut> apiMethod) { _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod)); } public IsSuccess ProcessApiMethod() { _result = _apiMethod(); // 用默认值判断值类型是否处理成功,可根据业务调整逻辑 return !EqualityComparer<TOut>.Default.Equals(_result, default) ? IsSuccess.Yes : IsSuccess.No; } public TOut? GetResult() { return _result; } }
完整优化代码
public enum IsSuccess { No = -1, NotSupported = 0, Yes = 1, WithoutContent = 2 } /// <summary> /// 策略模式基础接口(无返回值场景) /// </summary> public interface ISuccessConverterStrategy { IsSuccess ProcessApiMethod(); } /// <summary> /// 带返回值的策略模式接口 /// </summary> /// <typeparam name="TOut">返回值类型</typeparam> public interface ISuccessConverterStrategy<TOut> : ISuccessConverterStrategy { /// <summary> /// 获取处理结果: /// - 引用类型:处理失败/无结果时返回null /// - 值类型:处理失败时返回默认值 /// </summary> /// <returns></returns> TOut? GetResult(); } /// <summary> /// 策略模式上下文类 /// </summary> public class SilentSuccessConverter { public IsSuccess Convert(ISuccessConverterStrategy strategy, out string errorMessage) { if (strategy == null) { throw new NullReferenceException(nameof(strategy)); } errorMessage = string.Empty; try { return strategy.ProcessApiMethod(); } catch (Exception e) when (e.Message.ToLower().Contains("not implemented")) { errorMessage = $" - 消息: {e.Message} - 来源: {e.Source}{Environment.NewLine}"; return IsSuccess.NotSupported; } catch (Exception e) { errorMessage = $" - 消息: {e.Message} - 来源: {e.Source}{Environment.NewLine}"; if (e is NotImplementedException || e is NotSupportedException) { return IsSuccess.NotSupported; } return IsSuccess.No; } } } /// <summary> /// 处理返回引用类型的策略实现 /// </summary> /// <typeparam name="TOut"></typeparam> public class FuncReferenceTypeStrategy<TOut> : ISuccessConverterStrategy<TOut> where TOut : class { private Func<TOut> _apiMethod; private TOut _result; public void SetApiMethod(Func<TOut> apiMethod) { _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod)); } public IsSuccess ProcessApiMethod() { _result = _apiMethod(); return _result != null ? IsSuccess.Yes : IsSuccess.No; } public TOut? GetResult() { return _result; } } /// <summary> /// 处理返回值类型的策略实现 /// </summary> /// <typeparam name="TOut"></typeparam> public class FuncValueTypeStrategy<TOut> : ISuccessConverterStrategy<TOut> where TOut : struct { private Func<TOut> _apiMethod; private TOut _result; public void SetApiMethod(Func<TOut> apiMethod) { _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod)); } public IsSuccess ProcessApiMethod() { _result = _apiMethod(); // 根据业务逻辑判断值类型是否成功,这里用非默认值作为判断条件 return !EqualityComparer<TOut>.Default.Equals(_result, default) ? IsSuccess.Yes : IsSuccess.No; } public TOut? GetResult() { return _result; } } /// <summary> /// 带参数的无返回值策略实现 /// </summary> /// <typeparam name="TIn"></typeparam> public class ActionWithParamStrategy<TIn> : ISuccessConverterStrategy { private Action<TIn> _apiMethod; private TIn _input; public void SetApiMethod(Action<TIn> apiMethod, TIn input) { _input = input; _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod)); } public IsSuccess ProcessApiMethod() { _apiMethod(_input); return IsSuccess.Yes; } } /// <summary> /// 无参数的无返回值策略实现 /// </summary> public class ActionNoParamStrategy : ISuccessConverterStrategy { private Action _apiMethod; public void SetApiMethod(Action apiMethod) { _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod)); } public IsSuccess ProcessApiMethod() { _apiMethod(); return IsSuccess.Yes; } }
内容的提问来源于stack exchange,提问作者Nick Knatterton

