J'ai un bloc de code qui sérialise un type dans une balise HTML.
Type t = typeof(T); // I pass <T> in as a paramter, where myObj is of type T
tagBuilder.Attributes.Add("class", t.Name);
foreach (PropertyInfo prop in t.GetProperties())
{
object propValue = prop.GetValue(myObj, null);
string stringValue = propValue != null ? propValue.ToString() : String.Empty;
tagBuilder.Attributes.Add(prop.Name, stringValue);
}
Cela fonctionne très bien, sauf que je ne souhaite le faire que pour les types primitifs, comme int
, double
, bool
etc., et d’autres types qui ne sont pas primitifs mais peuvent l'être. sérialisé facilement comme string
. Je veux qu'il ignore tout le reste, comme les listes et autres types personnalisés.
Quelqu'un peut-il suggérer comment je fais cela? Ou dois-je spécifier les types que je veux autoriser quelque part et activer le type de la propriété pour voir s'il est autorisé? C'est un peu brouillon, alors ce serait bien si je faisais mieux.
Vous pouvez utiliser la propriété Type.IsPrimitive
, mais soyez prudent, car nous pouvons penser que certains types sont des primitives, mais ils ne le sont pas, par exemple Decimal
et String
.
Edition 1: Exemple de code ajouté
Voici un exemple de code:
if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(String) || ... )
{
// Is Primitive, or Decimal, or String
}
Edit 2: Comme @ SLaks , il existe d'autres types que vous souhaitez peut-être traiter comme des primitives. Je pense que vous devrez ajouter ces variations une par une.
Modifier 3: IsPrimitive = (Boolean, Octet, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, et Simple), type Anther Primitive-Like à vérifier (t == typeof (DateTime))
Je viens de trouver cette question tout en recherchant une solution similaire, et je pensais que l’approche suivante utilisant la méthode System.TypeCode
et System.Convert
.
Il est facile de sérialiser tout type mappé sur un System.TypeCode
autre que System.TypeCode.Object
, alors tu pourrais faire:
object PropertyValue = ...
if(Convert.GetTypeCode(PropertyValue) != TypeCode.Object)
{
string StringValue = Convert.ToString(PropertyValue);
...
}
L'avantage de cette approche est que vous n'avez pas à nommer tous les autres types non primitifs acceptables. Vous pouvez également modifier légèrement le code ci-dessus pour gérer tout type implémentant IConvertible.
Nous le faisons comme ça dans notre ORM:
Type t;
bool isPrimitiveType = t.IsPrimitive || t.IsValueType || (t == typeof(string));
Je sais que l'utilisation de IsValueType
n'est pas la meilleure option (vous pouvez avoir vos propres structures très complexes), mais cela fonctionne dans 99% des cas (et inclut Nullables).
À partir de la réponse @Ronnie Overby et du commentaire @jonathanconway, j'ai écrit cette méthode qui fonctionne pour Nullable et qui exclut les structures utilisateur.
public static bool IsSimpleType(Type type)
{
return
type.IsPrimitive ||
new Type[] {
typeof(Enum),
typeof(String),
typeof(Decimal),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
typeof(Guid)
}.Contains(type) ||
Convert.GetTypeCode(type) != TypeCode.Object ||
(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0]))
;
}
Avec le TestCase suivant:
struct TestStruct
{
public string Prop1;
public int Prop2;
}
class TestClass1
{
public string Prop1;
public int Prop2;
}
[Test]
public void Test1()
{
Assert.IsTrue(IsSimpleType(typeof(Enum)));
Assert.IsTrue(IsSimpleType(typeof(String)));
Assert.IsTrue(IsSimpleType(typeof(Char)));
Assert.IsTrue(IsSimpleType(typeof(Guid)));
Assert.IsTrue(IsSimpleType(typeof(Boolean)));
Assert.IsTrue(IsSimpleType(typeof(Byte)));
Assert.IsTrue(IsSimpleType(typeof(Int16)));
Assert.IsTrue(IsSimpleType(typeof(Int32)));
Assert.IsTrue(IsSimpleType(typeof(Int64)));
Assert.IsTrue(IsSimpleType(typeof(Single)));
Assert.IsTrue(IsSimpleType(typeof(Double)));
Assert.IsTrue(IsSimpleType(typeof(Decimal)));
Assert.IsTrue(IsSimpleType(typeof(SByte)));
Assert.IsTrue(IsSimpleType(typeof(UInt16)));
Assert.IsTrue(IsSimpleType(typeof(UInt32)));
Assert.IsTrue(IsSimpleType(typeof(UInt64)));
Assert.IsTrue(IsSimpleType(typeof(DateTime)));
Assert.IsTrue(IsSimpleType(typeof(DateTimeOffset)));
Assert.IsTrue(IsSimpleType(typeof(TimeSpan)));
Assert.IsFalse(IsSimpleType(typeof(TestStruct)));
Assert.IsFalse(IsSimpleType(typeof(TestClass1)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Char>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Guid>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Boolean>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Byte>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Int16>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Int32>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Int64>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Single>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Double>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<Decimal>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<SByte>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt16>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt32>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt64>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<DateTime>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<DateTimeOffset>)));
Assert.IsTrue(IsSimpleType(typeof(Nullable<TimeSpan>)));
Assert.IsFalse(IsSimpleType(typeof(Nullable<TestStruct>)));
}
Voici comment je l'ai fait.
static class PrimitiveTypes
{
public static readonly Type[] List;
static PrimitiveTypes()
{
var types = new[]
{
typeof (Enum),
typeof (String),
typeof (Char),
typeof (Guid),
typeof (Boolean),
typeof (Byte),
typeof (Int16),
typeof (Int32),
typeof (Int64),
typeof (Single),
typeof (Double),
typeof (Decimal),
typeof (SByte),
typeof (UInt16),
typeof (UInt32),
typeof (UInt64),
typeof (DateTime),
typeof (DateTimeOffset),
typeof (TimeSpan),
};
var nullTypes = from t in types
where t.IsValueType
select typeof (Nullable<>).MakeGenericType(t);
List = types.Concat(nullTypes).ToArray();
}
public static bool Test(Type type)
{
if (List.Any(x => x.IsAssignableFrom(type)))
return true;
var nut = Nullable.GetUnderlyingType(type);
return nut != null && nut.IsEnum;
}
}
Aussi une bonne possibilité:
private static bool IsPrimitiveType(Type type)
{
return (type == typeof(object) || Type.GetTypeCode(type) != TypeCode.Object);
}
En supposant que vous ayez une signature de fonction comme celle-ci:
void foo<T>()
Vous pouvez ajouter une contrainte générique pour autoriser uniquement les types de valeur:
void foo<T>() where T : struct
Notez que cela autorise non seulement les types primitifs pour T, mais tout type de valeur.
J'ai eu besoin de sérialiser des types dans le but de les exporter au format XML. Pour ce faire, j'ai itéré à travers l'objet et j'ai opté pour des champs de type primitif, enum, valeur ou sérialisable. C'était le résultat de ma requête:
Type contextType = context.GetType();
var props = (from property in contextType.GetProperties()
let name = property.Name
let type = property.PropertyType
let value = property.GetValue(context,
(BindingFlags.GetProperty | BindingFlags.GetField | BindingFlags.Public),
null, null, null)
where (type.IsPrimitive || type.IsEnum || type.IsValueType || type.IsSerializable)
select new { Name = name, Value = value});
J'ai utilisé LINQ pour parcourir les types, puis obtenir leur nom et leur valeur à stocker dans une table de symboles. La clé se trouve dans la clause "où" que j'ai choisie pour la réflexion. J'ai choisi des types de valeur primitifs, énumérés, sérialisables. Cela a permis aux chaînes et aux objets DateTime de passer comme je le souhaitais.
À votre santé!
Je veux juste partager ma solution. C'est peut-être utile à n'importe qui.
public static bool IsPrimitiveType(Type fieldType)
{
return fieldType.IsPrimitive || fieldType.Namespace.Equals("System");
}
C'est ce que j'ai dans ma bibliothèque. Les commentaires sont les bienvenus.
Je vérifie d'abord IsValueType, car il gère la plupart des types, puis String, puisqu'il s'agit du deuxième plus courant. Je ne peux pas penser à un primitif qui n'est pas un type de valeur, donc je ne sais pas si cette partie du si est jamais touchée.
Public Shared Function IsPersistable(Type As System.Type) As Boolean
With TypeInformation.UnderlyingType(Type)
Return .IsValueType OrElse Type = GetType(String) OrElse .IsPrimitive
End With
End Function
Public Shared Function IsNullable(ByVal Type As System.Type) As Boolean
Return (Type.IsGenericType) AndAlso (Type.GetGenericTypeDefinition() Is GetType(Nullable(Of )))
End Function
Public Shared Function UnderlyingType(ByVal Type As System.Type) As System.Type
If IsNullable(Type) Then
Return Nullable.GetUnderlyingType(Type)
Else
Return Type
End If
End Function
Ensuite, je peux l'utiliser comme ça:
Public Shared Function PersistableProperties(Item As System.Type) As IEnumerable(Of System.Reflection.PropertyInfo)
Return From PropertyInfo In Item.GetProperties()
Where PropertyInfo.CanWrite AndAlso (IsPersistable(PropertyInfo.PropertyType))
Select PropertyInfo
End Function
Voici une autre option viable.
public static bool CanDirectlyCompare(Type type)
{
return typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType;
}
public static bool IsPrimitiveType(object myObject)
{
var myType = myObject.GetType();
return myType.IsPrimitive || myType.Namespace == null || myType.Namespace.Equals("System");
}
N'oubliez pas de vérifier l'espace de noms NULL, car les objets anonymes n'ont pas d'espace de noms attribué.