微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

除非我先写入数据库,否则无法创建抽象类的实例

如何解决除非我先写入数据库,否则无法创建抽象类的实例

当我第一次尝试使用读取功能时,我遇到了两个错误,其中一个用于写入,一个用于读取:

反序列化类DDSRecorder.MessageContainer的Message属性时发生错误:无法创建抽象类的实例

这是我没有得到的,如果我至少先使用一次写入,则读取工作正常。我不明白在后台发生了什么,如果我们使用它编写一次,就可以初始化抽象类。

为其添加地图不能解决问题:

if (BsonClassMap.IsClassMapRegistered(typeof(MessageContainer)))
{
    BsonClassMap.RegisterClassMap<MessageBase>(cm =>
    {
        cm.AutoMap();
        cm.SetIsRootClass(true);
    });
}

这是我用于mongo集合的课程。

[BsonIgnoreExtraElements(true)]
public class MessageContainer
{
    [BsonId]
    public ObjectId Id { get; set; }

    [BsonDateTimeOptions(Kind = DateTimeKind.Utc)]
    public DateTime TimeStamp { get; set; }

    [BsonElement]
    public string MessageType { get; set; }

    public MessageBase Message { get; set; }

    [BsonConstructor]
    public MessageContainer()
    {

    }

    [BsonConstructor]
    public MessageContainer(MessageBase message)
    {
        Message = message ?? throw new ArgumentNullException(nameof(message));
        TimeStamp = DateTime.UtcNow;
        MessageType = message.GetType().Name;
    }

    [BsonConstructor]
    public MessageContainer(DateTime timeStamp,string messageType,MessageBase message)
    {
        TimeStamp = timeStamp;
        MessageType = messageType ?? throw new ArgumentNullException(nameof(messageType));
        Message = message ?? throw new ArgumentNullException(nameof(message));
    }  
}

里面的抽象类:

public abstract class MessageBase
    {
        protected MessageBase();

        public MessageBase Createcopy();
    }

写入方法示例:

public bool Write(MessageContainer message)
{
    if (message != null && _mongoCollection != null)
    {
        try
        {

            if (!BsonClassMap.IsClassMapRegistered(typeof(MessageContainer)))
            {
                BsonClassMap.RegisterClassMap<MessageContainer>();
                BsonClassMap.RegisterClassMap<MessageBase>(cm =>
                {
                    cm.AutoMap();
                    cm.SetIsRootClass(true);
                });
            }

            _mongoCollection.InsertOne(message);
           
            return true;                                      
        }
        catch (Exception Ex)
        {
            Console.WriteLine(Ex.Message);
        }
    }
    
    return false;
}

读取方法示例:

public bool GetFirstAndLastMessageTime(out DateTime firstMessageTime,out DateTime lastMessageTime)
{
  if (BsonClassMap.IsClassMapRegistered(typeof(MessageContainer)))
  {
      BsonClassMap.RegisterClassMap<MessageBase>(cm =>
      {
          cm.AutoMap();
          cm.SetIsRootClass(true);
      });
  }
  
  var filter = Builders<MessageContainer>.Filter.Empty;    
  var first = _mongoCollection.Find(filter).sort(Builders<MessageContainer>.sort.Ascending("TimeStamp")).Limit(5).ToList().First();
  var last = _mongoCollection.Find(filter).sort(Builders<MessageContainer>.sort.Descending("TimeStamp")).Limit(5).ToList().First();       
  firstMessageTime = first.TimeStamp; 
  lastMessageTime = last.TimeStamp;
  return true;
}

我缺少什么才能能够初始化抽象类而无需先编写?

解决方法

好吧,这里是一种反模式(我不喜欢将基类的依赖项添加到其实现中),但是快速解决方案是添加

[BsonKnownTypes(typeof(MyImplementation))]

其中MyImplementation是实现抽象类的类型。

在您的MessageBase班上

。对我来说,这样做很成功-我能够读取数据并进行反序列化。我也不必添加任何类映射。

,

尽管提供的阿米特拉答案是正确的,但由于多种原因,它对我而言并不起作用。

一个是我不想更改抽象类并将所有实现记为标签。

另一个要点是,我在MongoDB论坛上发现,显然只有写后才起作用的原因是自动映射器,这就是为什么写后才对我起作用的原因。

所以要做的就是我所做的:


public void RegisterClassMapping(List<string> messagesType)
{
    // Map base class first
    BsonClassMap.RegisterClassMap<MessageBase>(cm =>
    {
        cm.AutoMap();
        cm.SetIsRootClass(true);
    });

    if (messagesType.Count > 0)
    {
        foreach (string message in messagesType) // Do look up for each message
        {
            Type type = GetType("NAMEOFTHENAMESPACE." + message);

            if (type == null)
            {
                type = GetType("NAMEOFTHENAMESPACE." + message);
            }

            if (type != null && !BsonClassMap.IsClassMapRegistered(type))
            {
                BsonClassMap.LookupClassMap(type);
            }
        }
    }
}

这是我使用的通用GetType:

private Type GetType(string typeName)
{
    var type = Type.GetType(typeName);
    if (type != null) return type;

    foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
    {
        type = a.GetType(typeName);
        if (type != null)
            return type;
    }

    return null;
}

我只运行了一次,剩下的时间就可以使用了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。