将具有更多派生类型的通用对象分配/反序列化为具有较少派生类型的通用对象

时间:2016-03-27 10:57:29

标签: c# generics json.net covariance

我有一个具有以下结构的课程

public class GenericEntity<T>
    where T : BaseClass
{
    T Property {get; set;}
}

我有BaseClass的几个具体实现,并使用这些具体实现来实例化GenericEntity类型的对象

e.g。 var entity = new GenericEntity<DerivedClass>()

我通过将对象序列化为JSON(使用Newtonsoft)将此实体推送到消息传递框架中。在另一端,我从消息队列中提取该消息(JSON),并尝试使用JsonSerializerSettings GenericEntity<BaseClass>将消息反序列化为类型TypeNameHandling.All。但在反序列化时,它会抛出JsonSerializationException详细信息

  

在JSON&#39; NewtonsoftPlayground.GenericEntity 1[[NewtonsoftPlayground.DerivedClass, NewtonsoftPlayground, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], NewtonsoftPlayground, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not compatible with 'NewtonsoftPlayground.GenericEntity 1 [[NewtonsoftPlayground.BaseClass,NewtonsoftPlayground,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]],NewtonsoftPlayground,Version = 1.0中指定的类型。 0.0,Culture = neutral,PublicKeyToken = null&#39;。

我怎样才能做到这一点?或者我不应该使用通用?如果是这样,我最终会在从队列中提取消息后到处编写类型转换,我试图避免这种情况。

2 个答案:

答案 0 :(得分:1)

我重新创建了以下代码:

public class GenericEntity<T> where T : BaseClass 
    {
   public T Property { get; set; }
}

public class BaseClass {
}

class Derived1 : BaseClass
{
    public int Age { get; set; }
}

class Derived2 : BaseClass {
    public string Name { get; set; }
}

....

static void Main()
    {
        Derived1 d1 = new Derived1 {Age = 23};
        GenericEntity<Derived1> entity = new GenericEntity<Derived1> {Property = d1};

        var data = JsonConvert.SerializeObject(entity, new JsonSerializerSettings() {
            TypeNameHandling = TypeNameHandling.All
        });
        var baseEntity = JsonConvert.DeserializeObject(data, typeof(GenericEntity<BaseClass>));
}

反序列化数据时没有错误。请告诉我您的背景及其差异。

这显然不起作用:

        BaseClass d1 = new Derived1 {Age = 23};
        GenericEntity<BaseClass> entity = new GenericEntity<BaseClass> {Property = d1};

        var data = JsonConvert.SerializeObject(entity, new JsonSerializerSettings() {
            TypeNameHandling = TypeNameHandling.All
        });
        var baseEntity = JsonConvert.DeserializeObject<GenericEntity<Derived1>>(data, new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.All
        });

如果你序列化一个BaseClass,它将不负责序列化专门类所有的额外细节(我的意思是,你想序列化一个BaseClass,这正是你要序列化的)。

将它们序列化为专门的实例是你的工作:也就是说,如果你得到一个BaseClass并且你知道你需要Derived1将该实例解析为Derived1然后序列化它。

答案 1 :(得分:0)

我无法找到任何直接的解决方案来实现这一目标。正如@Tamas Ionut所建议的,在反序列化时指定基类不会反序列化具体类的属性。

作为一种解决方法,我创建了一个静态方法,它基本上实例化GenericEntity<BaseClass>并使用反射复制其中的所有属性。

    public static GenericEntity<BaseClass> ConvertToBaseEntity(object model)
    {
        if (model.GetType().GetGenericTypeDefinition() != typeof(GenericEntity<>))
        {
            throw new ArgumentException(
                "Model should be of type GenericEntity<T>.", "model");
        }

        GenericEntity<BaseClass> baseModel = new GenericEntity<BaseClass>();

        foreach (var propertyInfo in model.GetType().GetProperties())
        {
            baseModel.GetType().GetProperty(propertyInfo.Name).SetValue(baseModel, propertyInfo.GetValue(model));
        }

        return baseModel;
    }

我希望,这有助于某人。

相关问题