質問

I am trying to write an interface for a collection that internally stores data as a JObject

internal class JsonDataSet : IDataSet
{
    private JObject Document { get; set; }

    // The following methods are from the IDataSet interface
    public int Count { ... }
    public void Add<T>(string key, T value) { ... }
    public T GetItem<T>(string key) { ... }
    public bool ContainsKey(string key) { ... }
}

In the Add<T> method I want to provide a useful exception if a custom type does not have the DataContract annotation. For example, if someone calls:

dataSet.Add<IDictionary<string, IList<CustomType>>>(dict);

it will throw an exception "Cannot serialize type 'CustomType'. DataContract annotations not found." if CustomType does not have the proper annotation.

So far I have found a way to get every generic argument in the type definition so I can check them:

private IEnumerable<Type> GetGenericArgumentsRecursively(Type type)
{
    if (!type.IsGenericType) yield return type;

    foreach (var genericArg in type.GetGenericArguments())
        foreach (var yieldType in GetGenericArgumentsRecursively(genericArg ))
            yield return yieldType;
}

and tried implementing the add method like this:

public void Add<T>(string key, T value)
{
    foreach(var type in GetGenericArgumentsRecursively(typeof(T)))
    {
        if(!type.IsPrimitive && !Attribute.IsDefined(type, typeof(DataContractAttribute)))
            throw new Exception("Cannot serialize type '{0}'. DataContract annotations not found.", typeof(T));
    }

    Document.Add(new JProperty(key, JToken.Parse(JsonConvert.SerializeObject(value))));
}

I think this will work for primitive types and custom types but not for non-generic .NET types since they don't all have DataContract annotations. Is there a way to know which types can be serialized by JsonConvert?

役に立ちましたか?

解決

Json.NET supports pretty much all types, even those without any custom attributes. Among supported attributes are DataContract, JsonObject, Serializable. There're numerous ways to make Json.NET include a member in serialization and numerous to make it skip. If you can't serialize some class, it's more likely caused by issues other than lack of Data* attributes: members throwing exceptions, missing constructors, faulty converters, visibility issues etc. Your error messages are unlikely to be more helpful than those provided by Json.NET.

You'll have to replicate crazy amounts of logic from Json.NET if you want to test beforehand. Checking type and member attributes won't be enough. Just verifying a converter used for a property would require checking five places at least. And even if you do all this work, it will be not enough, because in a new version, a new type or converter or feature or attribute will be introduced in Json.NET and you'll have to do all this again.

The only reliable way to test wether a type can be serialized is to try to serialize it.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top