定义实现+运算符的泛型

时间:2010-08-30 06:30:59

标签: c# generics operators

  

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

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

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);

以这种方式在编译时强制执行所有操作:)

享受!

2 个答案:

答案 0 :(得分:8)

这是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,但这很麻烦且完全不安全:它会让你传入任何类型和调用任何方法或操作符,只在运行时崩溃,而不是在编译时崩溃。

答案 1 :(得分:1)

在C#4.0中,新的关键字动态允许您在运行时执行此操作。在以前的版本中它可能但对我来说太阴暗和棘手。但是你可以总是传递一个代理,它将在泛型中执行添加。否则它是不可能的,因为没有ISummable,IAdditive,一般来说,没有办法知道在编译时是什么是加法*。如果您希望进一步评论,我会在以后添加。 BR。

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