Vérification de type générique

Est-il possible d’imposer / limiter les types passés aux primitives? (bool, int, ssortingng, etc.)

Maintenant, je sais que vous pouvez limiter le paramètre de type générique à une implémentation de type ou d’interface via la clause where . Cependant, cela ne correspond pas à la facture pour les primitives (AFAIK) car elles n’ont pas toutes un terrain commun (hormis l’ object avant que quelqu’un ne dise: P).

Donc, mes pensées actuelles sont de serrer les dents et de faire un grand changement et de lancer une exception ArgumentException en cas d’échec.


EDIT 1:

Juste pour clarifier:

La définition du code devrait être comme suit:

public class MyClass .... 

Et instanciation:

 MyClass = new MyClass(); // Legal MyClass = new MyClass(); // Legal MyClass = new MyClass(); // Illegal MyClass = new MyClass(); // Illegal (but looks awesome!) 

EDIT 2

@Jon Limjap – Bon point, et quelque chose que je considérais déjà .. Je suis sûr qu’il existe une méthode générique qui peut être utilisée pour déterminer si le type est de type valeur ou référence.

Cela pourrait être utile pour supprimer instantanément un grand nombre des objects que je ne veux pas traiter (mais vous devez alors vous soucier des structures utilisées telles que la taille ). Problème intéressant non? 🙂

C’est ici:

 where T : struct 

Tiré de MSDN .


Je suis curieux .. Cela pourrait-il être fait dans .NET 3.x en utilisant des méthodes d’extension? Créez une interface et implémentez l’interface dans les méthodes d’extension (ce qui serait probablement plus propre qu’un switch fat). De plus, si vous devez ensuite étendre à des types personnalisés légers, ils peuvent également implémenter la même interface, sans aucune modification du code de base.

Qu’en pensez-vous?

Triste nouvelle, je travaille dans Framework 2 !! :RÉ


EDIT 3

C’était tellement simple de suivre Jon Limjaps Pointer .. Si simple que j’ai presque envie de pleurer, mais c’est génial car le code fonctionne comme un charme!

Alors voici ce que j’ai fait (tu vas rire!):

Code ajouté à la classe générique

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

Ensuite, une petite méthode utilitaire pour vérifier le type et lancer une exception,

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

Il suffit ensuite d’ appeler EnforcePrimitiveType () dans les constructeurs de classes. Travail terminé! 🙂

Le seul inconvénient, c’est qu’il ne lance qu’une exception lors de l’exécution (évidemment) plutôt que lors de la conception. Mais ce n’est pas grave et pourrait être utilisé avec des utilitaires comme FxCop (que nous n’utilisons pas au travail).

Un merci spécial à Jon Limjap sur celui-ci!

Les primitives semblent être spécifiées dans l’énumération TypeCode :

Peut-être existe-t-il un moyen de savoir si un object contient l’ TypeCode enum sans avoir à le TypeCode enum object spécifique ou à appeler GetType() ou typeof() ?

Mise à jour C’était juste sous mon nez. L’exemple de code montre ceci:

 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.ToSsortingng(), testObject); break; } } } 

C’est toujours un changement moche. Mais c’est un bon endroit pour commencer!

 public class Class1 where GenericType : struct { } 

Celui-ci semblait faire le travail ..

A peu près ce que @Lars a déjà dit:

 //Force T to be a value (primitive) type. public class Class1 where T: struct //Force T to be a reference type. public class Class1 where T: class //Force T to be a parameterless constructor. public class Class1 where T: new() 

Tous travaillent dans .NET 2, 3 et 3.5.

Si vous pouvez tolérer l’utilisation de méthodes d’usine (au lieu des constructeurs MyClass que vous avez demandés), vous pouvez toujours faire quelque chose comme ceci:

 class MyClass { private readonly T _value; private MyClass(T value) { _value = value; } public static MyClass FromInt32(int value) { return new MyClass(value); } public static MyClass FromSsortingng(ssortingng value) { return new MyClass(value); } // etc for all the primitive types, or whatever other fixed set of types you are concerned about } 

Un problème est que vous devez taper MyClass.FromInt32 , ce qui est agaçant. Il n’y a pas de moyen très efficace pour préserver la confidentialité du constructeur, mais voici quelques solutions:

  • Créez une classe abstraite MyClass . Rendre MyClass hériter de MyClass et l’imbriquer dans MyClass . Déplacez les méthodes statiques vers MyClass . Cela réduira toute la visibilité, au prix de devoir accéder à MyClass tant que MyClass.MyClass .
  • Utilisez MyClass comme indiqué. Créez une classe statique MyClass qui appelle les méthodes statiques dans MyClass utilisant MyClass (probablement en utilisant le type approprié à chaque fois, juste pour rire).
  • (Plus facile, mais certainement bizarre) Créez un type abstrait MyClass qui hérite de MyClass . (Pour être concret, disons MyClass .) Comme vous pouvez appeler des méthodes statiques définies dans une classe de base via le nom d’une classe dérivée, vous pouvez maintenant utiliser MyClass.FromSsortingng .

Cela vous donne une vérification statique au désortingment de plus d’écriture.

Si vous êtes satisfait de la vérification dynamic, j’utiliserais certaines variantes de la solution TypeCode ci-dessus.

@Rob, Enum va passer à travers la fonction TypeValid car son TypeCode est Integer . J’ai mis à jour la fonction pour rechercher également 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 

Vous pouvez simplifier la méthode EnforcePrimitiveType en utilisant la typeof(PrimitiveDataType).IsPrimitive . Est-ce que je manque quelque chose?

Utilisez une règle FxCop personnalisée qui MyClass<> utilisation indésirable de MyClass<> .

Ayant un défi similaire, je me demandais comment vous vous sentiez à propos de l’ interface IConvertible . Il permet ce que demande le demandeur et vous pouvez étendre vos propres implémentations.

Exemple:

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

Je pense à cela comme une solution, même si beaucoup des suggestions ont également fait partie de ma sélection.

Mon souci est – cependant – est-il trompeur pour les développeurs potentiels d’utiliser votre classe?

Cheers – et merci.