通用类型检查


71

有没有一种方法可以强制/限制传递给基元的类型? (布尔,整数,字符串等)

现在,我知道您可以通过where子句将泛型类型参数限制为类型或接口实现。但是,这并不适合基元(AFAIK),因为它们并不具有共同点(除了对象之前有人说过!:P)。

因此,我目前的想法是咬紧牙关,做一个大的switch语句,并在失败时抛出ArgumentException


编辑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-好点了,我已经考虑过了。.我确定有一种通用方法可以用来确定类型是值类型还是引用类型。

这在立即删除许多我不想处理的对象时可能很有用(但是您需要担心所使用的结构,例如Size)。有趣的问题不是吗?:)

这里是:

where T : struct

取自MSDN


我很好奇..这可以在.NET 3.x中使用扩展方法来完成吗?创建一个接口,并在扩展方法中实现该接口(这可能比使用胖开关更干净)。另外,如果您随后需要扩展到任何轻量级定制类型,则它们也可以实现相同的接口,而无需更改基本代码。

你们有什么感想?

不幸的消息是我正在Framework 2中工作!!:D


编辑3

这是从Jon Limjaps Pointer开始的非常简单的步骤。.非常简单,我几乎想哭了,但这很棒,因为代码像一个魅力一样起作用!

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

将代码添加到泛型类

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.");
}

接下来要做的就是在类构造函数中调用EnforcePrimitiveType()。任务完成!:-)

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

特别感谢乔恩·林贾普(Jon Limjap)!


您还可以在静态构造函数中调用检查,因此每个用作泛型参数的类型仅被调用一次。
朱利安

Answers:


40

似乎在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;
        }
    }
}

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


好吧,我不知道如何,但是对象和原始对象之间的争用要点是大多数原始对象实际上是结构,而不是类。我将寻找一种以编程方式解决它们的方法:)
乔恩·利姆贾普

好点了,这是我已经在考虑的问题。我确定有一个通用方法可以用来确定类型是值类型还是引用类型。这在立即删除很多对象时可能很有用。我不想处理(但随后您需要担心所使用的结构,例如Size)。:)编辑:嗯,是的,这里是:其中T:结构取自MSDN
罗伯·库珀

我很好奇..我想知道是否可以在.NET 3.x中使用扩展方法来完成..创建一个接口..在扩展方法中实现该接口..(这可能比一点胖的开关更干净) ..另外,如果您以后需要扩展到任何轻量级自定义类型,则它们也可以实现相同的接口,而无需更改基本代码。你们有什么感想?不幸的消息是我正在框架2中工作!!:D编辑:大概5分钟后离开办公室,等我回到家后,再接再厉!:D
罗伯·库珀

>公共类Class1 <GenericType>其中> GenericType:struct {}>>这个似乎可以完成工作。并非如此。
Jon Limjap


22

@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中。


4

如果您可以忍受使用工厂方法(而不是您要求的构造函数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<T>身份进行访问MyClass.MyClass<T>
  • MyClass<T>按给定使用。制作一个静态类MyClass,该类在MyClass<T>使用时调用静态方法MyClass<AnyTypeItDoesntMatter>(可能每次都使用适当的类型,仅用于咯咯笑)。
  • (更简单,但肯定很奇怪)制作一个MyClass 继承自MyClass<AnyTypeItDoesntMatter>的抽象类型。(具体说来MyClass<int>。)因为您可以通过派生类的名称调用基类中定义的静态方法,所以现在可以使用MyClass.FromString

这使您可以进行静态检查,但要花费更多时间。

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


3

@Rob,Enum的会滑过TypeValid,因为它的功能TypeCodeInteger。我已经更新了功能,还可以检查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



2

面临类似的挑战,我想知道你们对IConvertible接口的感觉如何。它允许请求者的要求,并且您可以扩展自己的实现。

例:

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

我正在考虑将其作为解决方案,尽管许多建议也是我选择的一部分。

但是,我担心的是-使用您的课程的潜在开发人员是否会产生误解?

干杯-谢谢。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.