通用类型检查

有没有强制/限制传递给原语的类型的方法? < em > (bool、 int、 string 等)

现在,我知道可以通过 哪里子句将泛型类型参数限制为类型或接口实现。然而,这并不符合原语(AFAIK)的要求,因为它们并不都有一个共同的基础(除了在有人说之前的 对象!校对: P)。

所以,我现在的想法是咬紧牙关,做一个大的 开关语句,在失败的时候抛出一个 异常


编辑1:

澄清一下:

代码定义应该是这样的:

public class MyClass<GenericType> ....

并举例说明:

MyClass<bool> = new MyClass<bool>(); // Legal
MyClass<string> = new MyClass<string>(); // Legal
MyClass<DataSet> = new MyClass<DataSet>(); // Illegal
MyClass<RobsFunkyHat> = new MyClass<RobsFunkyHat>(); // Illegal (but looks awesome!)

编辑2

@ Jon Limjap-说得好,我已经在考虑了。我确信有一个泛型方法可以用来确定类型是值类型还是引用类型。

这对于立即删除许多我不想处理的对象非常有用(但是您需要担心使用的结构,例如 大小)。有趣的问题,不是吗?:)

这就是:

where T: struct

取自 MSDN


我很好奇。这个可以在。NET 3.x 使用扩展方法?创建一个接口,并在扩展方法中实现该接口(这可能比位胖开关更简单)。另外,如果您以后需要扩展到任何轻量级自定义类型,它们也可以实现相同的接口,不需要对基本代码进行任何更改。

你们觉得怎么样?

坏消息是我在框架2里工作


编辑3

This was so simple following on from Jon Limjaps 指针.. So simple I almost want to cry, but it's great because the code works like a charm!

这就是我所做的(你们会笑的!) :

添加到泛型类的代码

bool TypeValid()
{
// Get the TypeCode from the Primitive Type
TypeCode code = Type.GetTypeCode(typeof(PrimitiveDataType));


// All of the TypeCode Enumeration refer Primitive Types
// with the exception of Object and Empty (Null).
// Since I am willing to allow Null Types (at this time)
// all we need to check for is Object!
switch (code)
{
case TypeCode.Object:
return false;
default:
return true;
}
}

然后使用一个小实用程序方法检查类型并抛出异常,

private void EnforcePrimitiveType()
{
if (!TypeValid())
throw new InvalidOperationException(
"Unable to Instantiate SimpleMetadata based on the Generic Type of '" + typeof(PrimitiveDataType).Name +
"' - this Class is Designed to Work with Primitive Data Types Only.");
}

接下来需要做的就是在类构造函数中调用 EnforcPrimitiveType ()

唯一的缺点是,它只在运行时(显然)而不是在设计时抛出异常。但这没什么大不了的,可以通过像 FxCop这样的实用程序(我们在工作中不使用它)来实现。

特别感谢 Jon Limjap!

29704 次浏览
public class Class1<GenericType> where GenericType : struct
{
}

这一个似乎做的工作. 。

使用自定义的 FxCop规则来标记 MyClass<>的不良用法。

基元似乎在 TypeCode枚举中指定:

也许有一种方法可以找出一个对象是否包含 TypeCode enum,而不必将其强制转换为特定的对象或调用 GetType()typeof()

更新 它就在我眼皮底下:

static void WriteObjectInfo(object testObject)
{
TypeCode    typeCode = Type.GetTypeCode( testObject.GetType() );


switch( typeCode )
{
case TypeCode.Boolean:
Console.WriteLine("Boolean: {0}", testObject);
break;


case TypeCode.Double:
Console.WriteLine("Double: {0}", testObject);
break;


default:
Console.WriteLine("{0}: {1}", typeCode.ToString(), testObject);
break;
}
}
}

这仍然是一个丑陋的开关。但它是一个很好的开始!

就像@Lars 已经说过的:

//Force T to be a value (primitive) type.
public class Class1<T> where T: struct


//Force T to be a reference type.
public class Class1<T> where T: class


//Force T to be a parameterless constructor.
public class Class1<T> where T: new()

所有工作在.NET 2,3和3.5。

如果您能够容忍使用工厂方法(而不是您要求的构造函数 MyClass) ,那么您总是可以这样做:

class MyClass<T>
{
private readonly T _value;


private MyClass(T value) { _value = value; }


public static MyClass<int> FromInt32(int value) { return new MyClass<int>(value); }
public static MyClass<string> FromString(string value) { return new MyClass<string>(value); }
// etc for all the primitive types, or whatever other fixed set of types you are concerned about
}

这里的一个问题是您需要键入 MyClass<AnyTypeItDoesntMatter>.FromInt32,这很烦人。如果你想保持构造函数的私有性,没有一个很好的解决方法,但是这里有一些变通方法:

  • 创建一个抽象类 MyClass。使 MyClass<T>MyClass继承 并将其嵌套在 MyClass。将静态方法移动到 MyClass。这将解决所有的可见性问题,代价是必须以 MyClass.MyClass<T>的形式访问 MyClass<T>
  • 使用给定的 MyClass<T>。使用 MyClass<AnyTypeItDoesntMatter>创建一个静态类 MyClass,它使用 MyClass<AnyTypeItDoesntMatter>调用 MyClass<T>中的静态方法(可能每次都使用适当的类型,只是为了好玩)。
  • (更容易,但肯定怪异)使一个抽象类型 MyClass 它继承自 MyClass<AnyTypeItDoesntMatter>。(为了具体起见,我们假设是 MyClass<int>。)因为可以通过派生类的名称调用在基类中定义的静态方法,所以现在可以使用 MyClass.FromString

这使您可以进行静态检查,而不必进行更多的写操作。

如果您对动态检查感到满意,我将使用上面的 TypeCode 解决方案的一些变体。

您可以使用 typeof(PrimitiveDataType).IsPrimitive属性简化 EnforcePrimitiveType方法。我是否遗漏了什么?

@ Rob,EnumTypeCodeInteger,所以 Enum会漏掉 TypeValid的功能。我已经更新了这个函数来检查 Enum

Private Function TypeValid() As Boolean
Dim g As Type = GetType(T)
Dim code As TypeCode = Type.GetTypeCode(g)


' All of the TypeCode Enumeration refer Primitive Types
' with the exception of Object and Empty (Nothing).
' Note: must also catch Enum as its type is Integer.
Select Case code
Case TypeCode.Object
Return False
Case Else
' Enum's TypeCode is Integer, so check BaseType
If g.BaseType Is GetType(System.Enum) Then
Return False
Else
Return True
End If
End Select
End Function

有一个类似的挑战,我想知道你们怎么看待 可转换接口。它支持请求者的需求,并且您可以使用自己的实现进行扩展。

例如:

    public class MyClass<TKey>
where TKey : IConvertible
{
// class intentionally abbreviated
}

我认为这是一个解决方案,虽然许多建议也是我选择的一部分。

但是,我担心的是,这会误导潜在的开发人员使用您的类吗?

干杯,谢谢。

在 dotnet 6中,我在使用 struct时遇到了这个错误:

类型‘ string’必须是非空值类型,才能将其用作参数‘ T’

所以我改用 IConvertable

var intClass = new PrimitivesOnly<int>();
var doubleClass = new PrimitivesOnly<double>();
var boolClass = new PrimitivesOnly<bool>();
var stringClass = new PrimitivesOnly<string>();
var myAwesomeClass = new PrimitivesOnly<MyAwesomeClass>(); // illegal


// The line below encounter issue when using "string" type
// class PrimitivesOnly<T> where T : struct
class PrimitivesOnly<T> where T : IConvertible
{
    

}


class MyAwesomeClass
{
}