13

当我使用 this.value 为 T 的泛型类尝试此操作时:

if (this.value.GetType() == typeof(int))
{
    ((int)this.value)++;
}
else
{
    throw new InvalidOperationException
            ("T must be an int to perform this operation");
}

我收到一个编译时错误:“无法将类型 'T' 转换为 'int'”

当 this.value 是 int 时,我应该怎么做才能对 this.value 执行积分运算?

请注意,这只是一个示例。该代码使用泛型进行类型转换,“int”只是 T 的一种类型的示例。

4

5 回答 5

24

不幸的是,很难让编译器相信特定的 T 实现。一种(讨厌的)方法是在中间强制转换为对象(注意这将装箱和拆箱值类型):

int i = (int)(object)this.value;
i++;
this.value = (T)(object)i;

丑陋但有效。在 .NET 3.5 中,我有一些更好的通用算术包装器,这里. Operator 类是MiscUtil的一部分;在最简单的层面上,我怀疑 AddAlternative 会很好地工作:

this.value = Operator.AddAlternative(this.value, 1);

这应该会自动推断出隐含的 <T,int> ,或者您可以自己添加它们:

this.value = Operator.AddAlternative<T,int>(this.value, 1);

好处:这比原始代码更可取,因为它实际上并不关心原始 T - 它适用于支持“T +(T,int)”的任何类型(甚至是您自己的)。

我认为那里的某个地方还隐藏着一个 ChangeType ......

[编辑] Collin K 和其他人对架构含义发表了有效的评论——但务实的时候,T 确实很重要……但我同意避免这种类型的专业化,除非真的有必要。也就是说(根据我对 Collin 帖子的评论),能够在(例如)Matrix<T> [for T in decimal/float/int/double/ 上执行基本算术(增量、Int32 除法等)等等]通常是非常有价值的。

于 2008-10-05T20:51:06.210 回答
12

在我看来,泛型类中特定于类型的代码是一种代码异味。我会重构它以获得这样的东西:

public class MyClass<T>
{
 ...
}

public class IntClass : MyClass<int>
{
  public void IncrementMe()
  {
    this.value++;
  }
}
于 2008-10-05T21:05:52.563 回答
3

C# 的静态类型不允许您这样做,但您可以通过强制转换为对象来欺骗它。我不建议这样做,它可能显示架构问题,但无论如何:

using System;

class Foo<T>
{
  public T value;

  public void Increment()
  {
   if (value is int) value = (T)(object)(((int)(object)value)+1);
  }
}

static class Program
{
    static void Main()
    {
     Foo<int> x = new Foo<int>();
     x.Increment();
     x.Increment();
      Console.WriteLine(x.value); 
    }     
}
于 2008-10-05T20:56:17.370 回答
0

我想我不明白你在追求什么。如果您要求某些东西是特定类型,那么您可能不应该使用泛型。你可以,只是看起来很傻。这将满足您的要求,但我不建议这样做。

namespace GenericsOne
{
    using System;

class Program
{
    static void Main(string[] args)
    {
        Sample<int> one = new Sample<int>();
        one.AddFive(10);

        // yes, this will fail, it is to show why the approach is generally not a good one.
        Sample<DateTime> two = new Sample<DateTime>();
        two.AddFive(new DateTime());
    }
}

}

namespace GenericsOne
{
    using System;
public class Sample<T>
{
    public int AddFive(T number)
    {
        int junk = 0;

        try
        {
            junk = Convert.ToInt32(number);
        }
        catch (Exception)
        {
            Console.WriteLine("Nope");
        }

        return junk + 5;
    }
}
}
于 2008-10-05T20:58:50.127 回答
0

这就是为什么我真的想要C#4 中的数字或操作约束。

@Marc Gravell 的回答是解决这个问题的最佳方法(+1),但令人沮丧的是,这对泛型来说是个问题。

于 2008-10-08T07:33:06.553 回答