Le meilleur moyen de tester si un type générique est une chaîne? (C #)


93

J'ai une classe générique qui devrait autoriser n'importe quel type, primitif ou autre. Le seul problème avec cela est d'utiliser default(T). Lorsque vous appelez default sur un type valeur ou une chaîne, il l'initialise à une valeur raisonnable (telle qu'une chaîne vide). Lorsque vous appelez default(T)un objet, il renvoie null. Pour diverses raisons, nous devons nous assurer que s'il ne s'agit pas d'un type primitif, nous aurons une instance par défaut du type, non null. Voici la tentative 1:

T createDefault()
{
    if(typeof(T).IsValueType)
    {
        return default(T);
    }
    else
    {
        return Activator.CreateInstance<T>();
    }
}

Problème - la chaîne n'est pas un type valeur, mais elle n'a pas de constructeur sans paramètre. Donc, la solution actuelle est:

T createDefault()
{
    if(typeof(T).IsValueType || typeof(T).FullName == "System.String")
    {
        return default(T);
    }
    else
    {
        return Activator.CreateInstance<T>();
    }
}

Mais cela ressemble à un kludge. Existe-t-il une meilleure façon de gérer la casse des chaînes?

Réponses:


161

Gardez à l'esprit que la valeur par défaut (chaîne) est null, pas une chaîne. Vous voudrez peut-être un cas particulier dans votre code:

if (typeof(T) == typeof(String)) return (T)(object)String.Empty;

2
Je pensais avoir essayé cette solution plus tôt et cela n'a pas fonctionné, mais j'ai dû faire quelque chose de stupide. Et merci d'avoir signalé que default (string) renvoie null, nous n'avons pas encore rencontré d'erreur à cause de cela, mais c'est vrai.
Rex M

1
@Matt Hamilton: +1, mais vous devez mettre à jour votre réponse pour renvoyer '(T) (object) String.Empty' comme suggéré par CodeInChaos car le type de retour de la méthode est générique, vous ne pouvez pas simplement renvoyer une chaîne.
VoodooChild

2
Et le ismot-clé? N'est-ce pas utile ici?
Naveed Butt

Pour le moment, il n'est pas possible d'appliquer l'opérateur is avec des génériques et une affectation ou une instanciation directe, n'est-ce pas?, Sera une fonctionnalité intéressante
Juan Pablo Garcia Coello

14
if (typeof(T).IsValueType || typeof(T) == typeof(String))
{
     return default(T);
}
else
{
     return Activator.CreateInstance<T>();
}

Non testé, mais la première chose qui m'est venue à l'esprit.


4

Vous pouvez utiliser l' énumération TypeCode . Appelez la méthode GetTypeCode sur les classes qui implémentent l'interface IConvertible pour obtenir le code de type d'une instance de cette classe. IConvertible est implémenté par Boolean, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, Decimal, DateTime, Char et String, afin que vous puissiez vérifier les types primitifs à l'aide de this. Plus d'informations sur " Vérification du type générique ".


2

Personnellement, j'aime la surcharge de méthodes:

public static class Extensions { 
  public static String Blank(this String me) {      
    return String.Empty;
  }
  public static T Blank<T>(this T me) {      
    var tot = typeof(T);
    return tot.IsValueType
      ? default(T)
      : (T)Activator.CreateInstance(tot)
      ;
  }
}
class Program {
  static void Main(string[] args) {
    Object o = null;
    String s = null;
    int i = 6;
    Console.WriteLine(o.Blank()); //"System.Object"
    Console.WriteLine(s.Blank()); //""
    Console.WriteLine(i.Blank()); //"0"
    Console.ReadKey();
  }
}


-6

La discussion pour String ne fonctionne pas ici.

Je devais avoir le code suivant pour les génériques pour que cela fonctionne -

   private T createDefault()
    { 

        {     
            if(typeof(T).IsValueType)     
            {         
                return default(T);     
            }
            else if (typeof(T).Name == "String")
            {
                return (T)Convert.ChangeType(String.Empty,typeof(T));
            }
            else
            {
                return Activator.CreateInstance<T>();
            } 
        } 

    }

3
Tester Stringpar nom, surtout sans tenir compte d'un espace de noms, est mauvais. Et je n'aime pas non plus la façon dont vous convertissez.
CodesInChaos
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.