Generic type checking

心已入冬 提交于 2019-11-29 18:41:37
Jon Limjap

Primitives appear to be specified in the TypeCode enumeration:

Perhaps there is a way to find out if an object contains the TypeCode enum without having to cast it to an specific object or call GetType() or typeof()?

Update It was right under my nose. The code sample there shows this:

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

It's still an ugly switch. But it's a good place to start!

public class Class1<GenericType> where GenericType : struct
{
}

This one seemed to do the job..

Keith

Pretty much what @Lars already said:

//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()

All work in .NET 2, 3 and 3.5.

If you can tolerate using factory methods (instead of the constructors MyClass you asked for) you could always do something like this:

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
}

A problem here is that you would need to type MyClass<AnyTypeItDoesntMatter>.FromInt32, which is annoying. There isn't a very good way around this if you want to maintain the private-ness of the constructor, but here are a couple of workarounds:

  • Create an abstract class MyClass. Make MyClass<T> inherit from MyClass and nest it within MyClass. Move the static methods to MyClass. This will all the visibility work out, at the cost of having to access MyClass<T> as MyClass.MyClass<T>.
  • Use MyClass<T> as given. Make a static class MyClass which calls the static methods in MyClass<T> using MyClass<AnyTypeItDoesntMatter> (probably using the appropriate type each time, just for giggles).
  • (Easier, but certainly weird) Make an abstract type MyClass which inherits from MyClass<AnyTypeItDoesntMatter>. (For concreteness, let's say MyClass<int>.) Because you can call static methods defined in a base class through the name of a derived class, you can now use MyClass.FromString.

This gives you static checking at the expense of more writing.

If you are happy with dynamic checking, I would use some variation on the TypeCode solution above.

@Rob, Enum's will slip through the TypeValid function as it's TypeCode is Integer. I've updated the function to also check for 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

You can simplify the EnforcePrimitiveType method by using typeof(PrimitiveDataType).IsPrimitive property. Am I missing something?

JoshL

Use a custom FxCop rule that flags undesirable usage of MyClass<>.

Having a similar challenge, I was wondering how you guys felt about the IConvertible interface. It allows what the requester requires, and you can extend with your own implementations.

Example:

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

I am thinking about this as a solution, all though many of the suggested was part of my selection also.

My concern is - however - is it misleading for potential developers using your class?

Cheers - and thanks.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!