Преобразование типов с помощью дженериков и наследования - PullRequest
0 голосов
/ 11 ноября 2019

Я представляю вам проблему, проблема возникает из NullReferenceException, из-за того, что когда я конвертирую свой объект DofusClient в TClient с помощью оператора As, который возвращает мне ноль (неправильная причина приведения). Я не понимаю, почему компилятор отказывает мне в этом приведении, в то время как TClient при вызове моего класса является объектом типа AuthClient, который наследует DofusClient, тогда я добавил его в предложение where моего класса Frame Manager.

public class FrameManager<TClient> : IFrameManager where TClient : DofusClient
   {
       private readonly ImmutableDictionary<int, Action<TClient, IDofusMessage>> m_frames;
       private IContextHandler m_threading;

       public FrameManager(ImmutableDictionary<int, Action<TClient, IDofusMessage>> frames,
           IContextHandler threading)
       {
           this.m_frames = frames;
           this.m_threading = threading;
       }

       public void Execute<TMessage>(DofusClient client, TMessage message) where TMessage : IDofusMessage
       {
           if (!m_frames.TryGetValue(message.ProtocolId, out var method))
               Logger.Instance.Log(LogLevel.Warn, "NETWORK-FRAME", $"Message id {message.ProtocolId} exists but isn't listed on frames.");
           else
           {
               Logger.Instance.Log(LogLevel.Info, "NETWORK-FRAME", $"Message Id {message.ProtocolId} has been parsed and treated.");

               m_threading.ExecuteInContext(() => method(client as TClient, message));
           }
       }
   }

public class FrameBuilder<TClient>
   {
       private readonly ImmutableDictionary<int, Action<TClient, IDofusMessage>>.Builder m_frames;

       public FrameBuilder()
       { this.m_frames = ImmutableDictionary.CreateBuilder<int, Action<TClient, IDofusMessage>>(); }


       public FrameBuilder<TClient> RegisterFrame<TFrame>() where TFrame : IFrame, new()
       {
           IFrame frame = new TFrame();
           Action<TClient, IDofusMessage> del;
           MessageHandlerAttribute attribute;
           IEnumerable<MethodInfo> methods = frame.GetType()
                                                   .GetMethods()
                                                   .Where(x => (x.GetCustomAttribute(typeof(MessageHandlerAttribute))
                                                   as MessageHandlerAttribute) != null);
           foreach (MethodInfo method in methods)
           {
               attribute = (MessageHandlerAttribute)method.GetCustomAttribute(typeof(MessageHandlerAttribute));

               del = Delegate.CreateDelegate(typeof(Action<TClient, IDofusMessage>), null, method)
                     as Action<TClient, IDofusMessage>;

               m_frames.Add(attribute.MessageId, del);

           }

           Logger.Instance.Log(LogLevel.Debug, $"FRAME-BUILDER",
               $"{ methods.Count()} methods handled from {typeof(TFrame).Name}.");

           return this;
       }

       public ImmutableDictionary<int, Action<TClient, IDofusMessage>> Build()
       { return m_frames.ToImmutable(); }
   }


public class FrameDispatcher
   {
       private readonly ImmutableDictionary<int, Func<IDofusMessage>> m_messageProvider;
       private readonly IFrameManager m_frameManager;

       public FrameDispatcher(ImmutableDictionary<int, Func<IDofusMessage>> messageProvider, IFrameManager frameManager)
       {
           this.m_messageProvider = messageProvider;
           this.m_frameManager = frameManager;
       }

       public void Dispatch(DofusClient client, Frame<DofusMetadata> frame)
       {
           int key = frame.Metadata.MessageId;

           if (!m_messageProvider.TryGetValue(key, out var msgCtor))
               Logger.Instance.Log(LogLevel.Warn,"[NETWORK]", $"The message received isn't in the protocol : {key}.");
           else
           {
               IDofusMessage message = msgCtor();
               var reader = new DofusReader(frame.Payload);

               message.Deserialize(reader);
               m_frameManager.Execute(client, message);
           }

       }

    public class IdentificationFrame : IFrame
    {
        [MessageHandler(IdentificationMessage.NetworkId)]
        public void HandleIdentificationMessage(AuthClient client, IDofusMessage msg)
        {
            var message = msg as IdentificationMessage;
            /*Here AuthClient is null*/
           _= client.SendMessageAsync(new IdentificationSuccessMessage()
                .InitIdentificationSuccessMessage("test", "null", 1, 0, new WrappedBool(false), "lol", 12222, 222, 000222
                , new WrappedBool(false), 0));
        }

    }

Конечно, было бы проще напрямую поместить тип AuthClient в Frame Builder.cs и Frame Manager.Cs, но проект разделен на несколько сборок, где AuthClient отсутствует в сборке других классов. Кроме того, FrameBuilder / FrameManager будет повторно использоваться для данных другого типа, поэтому я не предпочитаю повторяться в коде.

Спасибо за чтение и хорошего дня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...