Я представляю вам проблему, проблема возникает из 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 будет повторно использоваться для данных другого типа, поэтому я не предпочитаю повторяться в коде.
Спасибо за чтение и хорошего дня.