【问题标题】:Define a generic that implements the + operator [duplicate]定义一个实现 + 运算符的泛型 [重复]
【发布时间】:2011-04-05 15:05:47
【问题描述】:

可能重复:
Solution for overloaded operator constraint in .NET generics

我正在处理一个问题,目前它适用于 ints,但我希望它适用于可以使用 + 运算符添加的所有类。有没有办法在泛型中定义它?例如,

public List<T> Foo<T>() where T : ISummable

有什么办法吗?

编辑:
传入委托进行求和而不是使用 += 与 Int 类型的性能最多慢 540%。研究可能的其他解决方案

最终解决方案:
谢谢大家的建议。我最终得到了一个不太慢并在编译时强制检查的解决方案。我不能完全相信一位同事帮助我做到了这一点。无论如何,这里是:

以函数的形式实现一个包含所有必需运算符的接口

public interface IFoo<InputType, OutputType>
{
    //Adds A to B and returns a value of type OutputType
    OutputType Add(InputType a, InputType b);
    //Subtracts A from B and returns a value of type OutputType
    OutputType Subtract(InputType a, InputType b);
}

创建您要定义的类,但不要使用 Where 子句,而是使用 IFoo 接口的依赖注入实例。由于运算的性质是数学的,因此 OutputType 通常是双倍的。

public class Bar<T>
{
    private readonly IFoo<T,double> _operators;

    public Bar(IFoo<T, double> operators)
    {
        _operators = operators;
    }
}

现在当你使用这个类时,你可以像这样定义操作规则:

private class Foo : IFoo<int, double>
{
    public double Add(int a, int b)
    {
        return (double)(a+b);
    }
    public double Subtract(int a, int b)
    {
        return (double)(a-b);
    }
}

那么你会像这样使用它:

Foo inttoDoubleOperations = new Foo();
Bar myClass = new Bar(Foo);

这样所有操作都在编译时执行:)

享受吧!

【问题讨论】:

  • 不,不直接。但是有一篇关于 CodeProject 的文章模拟了这一点。
  • 感谢您的回复。你能给我一个解决方案的链接吗?
  • 为什么没有 ISummable 中可以添加两个 T 的方法,例如 T Add(T first, T second)?使用 + 运算符进行加法将 IMO 涉及反射调用 op_Addition 方法。
  • @Timwi:除了动态会慢很多。所以它并没有过时。
  • @TerrorAustralis:如果我手头有网址,我会发布的。我记得几年前看到它的事实并不意味着我仍然拥有该链接。

标签: c# generics operators


【解决方案1】:

这是 C# 非常普遍要求的新特性:能够指定比我们已有的更通用的参数约束。操作员是最常被问到的问题之一。但是,C# 目前不支持此功能。

可能的解决方法:

  • 将委托传递给任何需要添加的方法。这是最类型安全的选项,但是如果您需要经常调用这样的方法当然会很烦人。例如:

    public class Generic<T> {
        public void DoSomething(T anItem, T anotherItem, Func<T, T, T> add) {
            // instead of
            Blah(anItem + anotherItem);
            // have to write:
            Blah(add(anItem, anotherItem));
        }
    }
    
    Generic<int> genInt = ...;
    // and then instead of ...
    genInt.DoSomething(1, 2);
    // have to write:
    genInt.DoSomething(1, 2, (a, b) => a + b);
    
  • 声明你自己的接口IAddable然后你可以把它作为一个泛型类型参数约束,但是显然你不能使用int作为参数。您必须使用自己的 struct,其中仅包含 int 并实现 IAddable

    public interface IAddable<T> {
        T Add(T other);
    }
     
    public struct Integer : IAddable<Integer> {
        public int Value;
        public Integer(int value) { Value = value; }
        public Integer Add(Integer other) { return new Integer(Value + other.Value); }
    }
    
    // then instead of
    Generic<int> blah = ...;
    // have to write:
    Generic<Integer> blah = ...;
    
  • dynamic. 另一种可能的解决方法是使用dynamic,但这相当hacky且完全不安全:它会让您传入任何类型并调用任何方法或运算符,并且只在运行时崩溃,而不是在编译时。

【讨论】:

  • 谢谢,我最终可能会采用传递代表的方法。这似乎是一个合理的解决方法,不会给用户增加太多的努力。谢谢老哥!
【解决方案2】:

在 C# 4.0 中,新关键字 dynamic 允许您在运行时执行此操作。在以前的版本中,这是可能的,但对我来说太阴暗和棘手了。但是你总是可以传递一个在泛型中执行添加的委托。否则这是不可能的,因为没有 ISummable、IAdditive 并且一般来说没有办法知道在编译时某些东西是加法的*。如果您希望获得更多的 cmets,我将在稍后添加。 BR。

  • 我的意思是,除了让您拥有 IAdditive 并用它们标记一些类型,但它不适用于例如 int。

【讨论】:

  • 感谢您的回复!您对 IAdditive 的评论一针见血。我不能为整数和其他预实现的类/结构工作
猜你喜欢
  • 2023-03-29
  • 2015-05-23
  • 1970-01-01
  • 2012-12-10
  • 2014-01-01
  • 1970-01-01
  • 2017-04-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多