我向您提出问题,该问题来自NullReferenceException
,这是由于以下事实:当我通过As运算符将DofusClient对象转换为TClient时,返回给我的结果为null(错误的转换原因)。我看不到为什么编译器在调用TClass时拒绝我在TClient时执行此强制转换,而该继承是AuthClient
类型的DofusClient
类型的对象,然后将其添加到类Frame Manager的where子句中。
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,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,$"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,IDofusMessage>>.Builder m_frames;
public FrameBuilder()
{ this.m_frames = ImmutableDictionary.CreateBuilder<int,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,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,new WrappedBool(false),"lol",12222,222,000222,0));
}
}
当然,将AuthClient类型直接放置在Frame Builder.cs和Frame Manager.Cs中会更容易,但是该项目被分为几个程序集,而AuthClient不在其他类的程序集中。另外,FrameBuilder / FrameManager将被重用于另一种类型的数据,因此我不想在代码中重复我自己。
感谢阅读,祝您愉快。