Question

Existe-t-il un moyen d'appliquer/limiter les types transmis aux primitives ? (bool, int, chaîne, 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 le clause.Cependant, cela ne convient pas aux primitives (AFAIK) car elles n'ont pas toutes un terrain d'entente (à part objet avant que quelqu'un ne le dise !:P).

Donc, mes pensées actuelles sont de serrer les dents et de faire un grand changer déclaration et lancer un ArgumentException en cas d'échec..


MODIFICATION 1 :

Juste pour clarifier:

La définition du code devrait ressembler à :

public class MyClass<GenericType> ....

Et instanciation :

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!)

MODIFIER 2

@Jon Limjap - Bon point, et quelque chose que j'envisageais 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 d'objets que je ne veux pas gérer (mais vous devez alors vous soucier des structures utilisées telles que Taille )..Problème intéressant non ?:)

C'est ici:

where T : struct

Pris à partir de MSDN.


Je suis curieux..Cela pourrait-il être fait dans .NET 3.x à l’aide de 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 gros commutateur).De plus, si vous devez ensuite étendre ultérieurement à des types personnalisés légers, ils peuvent également implémenter la même interface, sans aucune modification requise dans le code de base.

Qu'en pensez-vous?

La triste nouvelle est que je travaille dans Framework 2 !!:D


MODIFIER 3

C'était si simple à la suite de Jon Limjaps Pointeur..Tellement simple que j'en ai presque envie de pleurer, mais c'est génial car le code fonctionne à merveille !

Alors voici ce que j'ai fait (vous allez 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;
    }
}

Puis une petite méthode utilitaire pour vérifier le type et lever 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 ne reste plus qu'à appeler AppliquerPrimitiveType() dans les constructeurs de classes.Travail accompli!:-)

Le seul inconvénient, il ne lève une exception qu'au moment de l'exécution (évidemment) plutôt qu'au moment de la conception.Mais ce n'est pas grave et pourrait être récupéré avec des services publics comme FxCop (que nous n'utilisons pas au travail).

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

Était-ce utile?

La solution

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

Il existe peut-être un moyen de savoir si un objet contient le TypeCode enum sans avoir à le convertir en un objet ou un appel spécifique 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.ToString(), testObject);
            break;
        }
    }
}

C'est toujours un vilain changement.Mais c'est un bon point de départ !

Autres conseils

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

Celui-ci semblait faire le travail..

C'est à peu près ce que @Lars a déjà dit :

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

Tous fonctionnent 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<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
}

Un problème ici est que vous devrez taper MyClass<AnyTypeItDoesntMatter>.FromInt32, ce qui est ennuyeux.Il n’existe pas de très bonne solution si vous souhaitez conserver le caractère privé du constructeur, mais voici quelques solutions :

  • Créer une classe abstraite MyClass.Faire MyClass<T> hériter de MyClass et imbriquez-le à l'intérieur MyClass.Déplacez les méthodes statiques vers MyClass.Cela permettra à toute la visibilité de fonctionner, au prix de devoir accéder MyClass<T> comme MyClass.MyClass<T>.
  • Utiliser MyClass<T> comme donné.Créer une classe statique MyClass qui appelle les méthodes statiques dans MyClass<T> en utilisant MyClass<AnyTypeItDoesntMatter> (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<AnyTypeItDoesntMatter>.(Pour être plus concret, disons MyClass<int>.) Étant donné que 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 désormais utiliser MyClass.FromString.

Cela vous donne une vérification statique au détriment de plus d'écriture.

Si vous êtes satisfait de la vérification dynamique, j'utiliserais une variante de la solution TypeCode ci-dessus.

@Rob, Enumça va glisser à travers le TypeValid fonctionner comme il est TypeCode est Integer.J'ai mis à jour la fonction pour vérifier é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 le EnforcePrimitiveType méthode en utilisant typeof(PrimitiveDataType).IsPrimitive propriété.Est-ce que j'ai raté quelque chose ?

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

Ayant un défi similaire, je me demandais ce que vous pensiez du Interface convertible.Il permet ce dont le demandeur a besoin et vous pouvez l'étendre avec vos propres implémentations.

Exemple:

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

Je considère cela comme une solution, même si la plupart des solutions suggérées faisaient également partie de ma sélection.

Ma préoccupation est - cependant - est-ce trompeur pour les développeurs potentiels utilisant votre classe ?

Bravo - et merci.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top