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

能否通过泛型约束(when)实现泛型类中各类运算符的合法调用?

Great question! Let's break this down clearly—C# doesn't let you directly use operators like < (or any of the operators you listed: +, -, !, ~, ++, --, *, /, %, &, |, ^, <<, >>, ==, !=, <, >, <=, >=) on a generic type T just with a basic when constraint out of the box. But there are several proven patterns to make this work, tailored to your .NET version and requirements.

Key Limitation Up Front

The core issue is that prior to .NET 7, there were no built-in interfaces that represent operator support (like "this type can be compared with <" or "this type can be added"). The when keyword only lets you constrain T to types that implement specific interfaces, inherit from a base class, or meet other narrow criteria—none of which directly map to operator support.


1. .NET 7+ Use Generic Math (Best Option)

If you're targeting .NET 7 or newer, Microsoft introduced Generic Math interfaces (like INumber<T>, IComparable<T>, IAdditionOperators<T,T,T>, etc.) that explicitly model operator support. This lets you use operators directly in generic code with full compile-time safety.

using System.Numerics;

public class MyClass<T> where T : INumber<T>
{
    public void MyMethod(T a, T b)
    {
        // All these operators work directly!
        bool isLessThan = a < b;
        T sum = a + b;
        bool areEqual = a == b;
        T product = a * b;
        bool isNotEqual = a != b;
        // ... and all other operators you listed
    }
}

Pros: Type-safe, performant, and the most idiomatic modern approach. Covers all numeric operators and comparisons.
Cons: Requires .NET 7 or later.

2. Use Interface Constraints + Explicit Method Calls (Pre-.NET 7)

For comparison operators (like <, >, <=, >=), you can constrain T to IComparable<T> and use the CompareTo method instead of direct operators. For arithmetic operators, you'd need custom interfaces (or use the next pattern).

public class MyClass<T> where T : IComparable<T>
{
    public void MyMethod(T a, T b)
    {
        // Replace a < b with CompareTo check
        bool isLessThan = a.CompareTo(b) < 0;
        bool isGreaterThan = a.CompareTo(b) > 0;
        bool areEqual = a.CompareTo(b) == 0;
        // ...
    }
}

Pros: Compile-time type safety, works on all .NET versions.
Cons: Doesn't support arithmetic operators out of the box—you'd have to define your own interfaces (e.g., IAddable<T>) and implement them for types you want to use.

3. Pass Operator Delegates (Flexible for All Operators)

If you need to support any operator (including arithmetic) on pre-.NET 7 versions, you can pass delegates that encapsulate the operator logic when instantiating your generic class. This gives you full flexibility for any operator.

public class MyClass<T>
{
    // Store delegates for the operators you need
    private readonly Func<T, T, bool> _lessThanOperator;
    private readonly Func<T, T, T> _additionOperator;
    private readonly Func<T, T, bool> _equalityOperator;

    public MyClass(
        Func<T, T, bool> lessThanOperator,
        Func<T, T, T> additionOperator,
        Func<T, T, bool> equalityOperator)
    {
        _lessThanOperator = lessThanOperator ?? throw new ArgumentNullException(nameof(lessThanOperator));
        _additionOperator = additionOperator ?? throw new ArgumentNullException(nameof(additionOperator));
        _equalityOperator = equalityOperator ?? throw new ArgumentNullException(nameof(equalityOperator));
    }

    public void MyMethod(T a, T b)
    {
        bool isLessThan = _lessThanOperator(a, b);
        T sum = _additionOperator(a, b);
        bool areEqual = _equalityOperator(a, b);
        // ...
    }
}

// Usage example
var intClass = new MyClass<int>(
    (x, y) => x < y,
    (x, y) => x + y,
    (x, y) => x == y);
intClass.MyMethod(3, 5);

Pros: Supports every operator you listed, works on all .NET versions.
Cons: Requires passing delegates at instantiation, which adds boilerplate.

4. Use dynamic (Quick but Unsafe)

As a last resort, you can cast T to dynamic to bypass compile-time checks. This lets you use operators directly, but you lose type safety—you'll only get errors at runtime if T doesn't support the operator.

public class MyClass<T>
{
    public void MyMethod(T a, T b)
    {
        // Runtime check only—no compile-time safety
        bool isLessThan = (dynamic)a < (dynamic)b;
        T sum = (dynamic)a + (dynamic)b;
        // ...
    }
}

Pros: No boilerplate, works with any type that supports the operator.
Cons: No compile-time validation, potential runtime exceptions, and slightly worse performance due to dynamic dispatch.


Summary

  • If you can use .NET 7+: Go with Generic Math interfaces (INumber<T> etc.)—it's the cleanest, safest solution.
  • Pre-.NET 7 for comparisons: Use IComparable<T> and CompareTo.
  • Pre-.NET 7 for all operators: Use delegate injection for full flexibility.
  • Avoid dynamic unless you're okay with runtime risks.

内容的提问来源于stack exchange,提问作者Christophe Debove

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:13:22