【问题标题】:Using generic constraints with value types对值类型使用泛型约束
【发布时间】:2011-10-06 15:17:45
【问题描述】:

我正在尝试流畅的扩展方法。

我有以下简单的扩展方法来执行安全强制转换。

     public static T As<T>(this Object source)
         where T : class
     {
         return source as T;
     }

这很好用,但是当我试图直观地使用带有重载的值类型时

     public static T As<T>(this ValueType source)
         where T : struct
     {
         return (T)source;
     }

我遇到了问题。方法解析逻辑总是选择上面的第一个方法,并给出一个语法错误(准确地说)结构不是一个类。

有没有办法处理上述问题,或者我应该在以同一方法测试和处理所有类型的同时消除约束?

==== 编辑:回答问题====

我正在针对 3.5 框架进行编译。我并没有特别想完成任何事情。这只是上面的一个实验。我的兴趣被激起了,我拼凑了一些代码。

我并不特别担心它仍然是一个“安全”的演员阵容。这就是它的开始方式,并且可以使用 default() 保持安全——但这并不是问题的真正重点,确保“安全”的代码只是模糊不清。

在表现力方面,没有value.As&lt;int&gt;() 不比(int)value 更具表现力;但是为什么该方法的用户必须“只知道”它只适用于引用类型?我尝试使用它更多的是关于方法的预期行为,而不是表达性写作。

代码 sn-p value.As&lt;DateTime&gt;() 给出错误“类型 'System.DateTime' 必须是引用类型才能将其用作泛型类型或方法中的参数 'T' ....As(目的)”。从错误消息中,我看到它正在解决使用上面的方法,因为它是需要引用类型的方法。

【问题讨论】:

  • 您使用的是什么版本的 C#?在 .NET 4 中,选择了第二个重载。
  • 您的意思是像object o = 42; var i = o.As&lt;int&gt;(); 这样给出语法错误的代码吗?或者你能显示给出它的确切代码吗?
  • @svick 的评论让我想起了您可能正在尝试对数据库结果执行的操作,例如 DataRow。如果是这样,则扩展方法已经到位,可以将行中的对象值转换为适当的类型。 .Field<T>

标签: c# generics extension-methods constraints fluent-interface


【解决方案1】:

在 .NET 4 中,根据您的代码示例选择第二个重载。 (也刚刚针对 .NET 3.5 进行了测试,结果相同。)

int myInt = 1;
long myLong = myInt.As<long>(); // chooses ValueType version

但是,这只会让我们进入下一次崩溃的现场。 (T)source; 导致无效的强制转换异常。您可以通过将方法编写为

来解决这个问题
public static T As<T>(this ValueType source)
    where T : struct
{
    return (T)Convert.ChangeType(source, typeof(T));
}

但是,我想知道您实际上想要实现什么,因为我没有看到直接的好处。 (就此而言,这并不像source as T 对象版本那样安全。)例如,

long myLong = myInt.As<long>();

比

更具表现力或更易于使用
long myLong = (long)myInt;

【讨论】:

  • 由于 ValueType 是——尽管它的名字——实际上是一个类类型,后一种表述需要对参数进行装箱。不幸的是,我真的不认为有任何方法可以使 .net 允许基于泛型参数的值类型进行重载。
猜你喜欢
  • 1970-01-01
  • 2011-01-17
  • 2017-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多