You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#泛型约束与策略模式实现问题求助

策略模式泛型约束问题及解决方案

背景

为消除冗余代码,我采用策略模式,将原冗余代码放入策略模式的上下文类中,该类会调用IsSuccess ProcessApiMethod()方法,上下文类无问题,仅作完整展示。

难点

  • ProcessApiMethod()方法在TOut为类类型时需返回null,但TOut也可为int、bool等值类型。

已解决部分

  • 部分API方法返回类型为void,因此我实现了两个不同接口。

当前问题

  1. C#是否支持备选泛型约束?
  2. 如何仅允许值类型作为T的可用类型?

我期望类似如下的约束写法:

public interface ISuccessConverterStrategy<TOut> where Tout : (class || basicType)

但如下写法无意义:

public interface ISuccessConverterStrategy<TOut> where Tout : (class || (!class && !struct))

若第一个问题答案为“否”,该如何解决?

目前无论如何尝试,策略类编译时均提示“未实现接口成员'TOut SuccessConverter.ISuccessConverterStrategy.GetResult()'”或其他泛型使用问题。


问题解答

  1. C#不支持备选泛型约束
    C#泛型约束仅支持交集逻辑,只能同时满足多个约束条件,无法使用||这类“或”逻辑的备选约束。如果你的需求是覆盖所有类型(引用类型+值类型),不需要添加任何约束——泛型参数默认即可接受任意类型。

  2. 仅允许值类型的泛型约束写法
    若要限制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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 20:45:38