実行時に基本クラスを派生クラスにキャストするにはどうすればよいですか。私がやろうとしていることは次のとおりです。特定のタイプのメッセージにサブスクライバーが割り当てられているサブスクリプションを保持するシステムが必要です。メッセージが受信されると、このシステムに転送されます。このシステムは、この種のメッセージのサブスクライバーが存在するかどうかを調べます。存在する場合、メッセージはサブスクライバーに転送されます。Response という抽象基本クラスがあり、その後に抽象レイヤーが続きます。AFResponse : 応答、そして実際の (具体的な) 実装があります。応答 (抽象) : AFResponse (抽象) : AFIncommingMessage (具体的)。
パケットが受信されると、MessageBuilder に送られ、メッセージ タイプが解決され、次のようにビルドされます。
public static T Build<T>(Packet packet) where T : Response
{
Type resolvedType;
if (!dependencyMap.TryGetValue(packet.MessageId, out resolvedType))
{
var str = String.Format("Could not resolve message. Message info: CMD0: {0}, CMD1: {1}, MessageID: {2}",
packet.Cmd0, packet.Cmd1, packet.MessageId);
Debug.WriteLine(str);
throw new ResolutionFailedException(str);
}
ConstructorInfo firstConstructor = resolvedType.GetConstructors().First();
return (T) firstConstructor.Invoke(new object[] {packet});
}
次に、メッセージが非同期の場合、メッセージ タイプのサブスクリプションを保持する MessageBinder に転送されます。
private void OnAsyncResponseReceived(Response response)
{
messageBinder.Forward(response);
}
MessageBinder クラスは次のように実装されます。
public class MessageBinder
{
private class Subscriber<T> : IEquatable<Subscriber<T>> where T : Response
{
...
}
private readonly Dictionary<Type, IEnumerable> bindings;
public MessageBinder()
{
this.bindings = new Dictionary<Type, IEnumerable>();
}
public void Bind<TResponse>(ushort shortAddress, Action<ZigbeeAsyncResponse<TResponse>> callback)
where TResponse : Response
{
HashSet<Subscriber<TResponse>> subscribers = this.GetSubscribers<TResponse>();
if (subscribers != null)
{
subscribers.Add(new Subscriber<TResponse>(shortAddress, callback));
}
else
{
var subscriber = new Subscriber<TResponse>(shortAddress, callback);
this.bindings.Add(typeof(TResponse), new HashSet<Subscriber<TResponse>> { subscriber });
}
}
public void Forward<TResponse>(TResponse response)
where TResponse : Response
{
var subscribers = this.GetSubscribers<TResponse>();
if (subscribers != null)
{
Subscriber<TResponse> subscriber;
var afResponse = response as AFResponse;
if (afResponse != null)
{
subscriber = subscribers.SingleOrDefault(s => s.ShortAddress == afResponse.ShortAddress);
}
else
{
subscriber = subscribers.FirstOrDefault();
}
if (subscriber != null)
{
Debug.WriteLine("Forwarding received async response of type " + response.GetType().Name);
subscriber.Forward(response);
}
}
}
private HashSet<Subscriber<TResponse>> GetSubscribers<TResponse>() where TResponse : Response
{
IEnumerable subscribers;
this.bindings.TryGetValue(typeof(TResponse), out subscribers);
return (HashSet<Subscriber<TResponse>>)subscribers;
}
}
MessageBinder クラスのメソッド GetSubscribers() が呼び出されると、TResponse の型が Response である基本クラスの型であるため、サブスクライバーが見つからないため、問題が発生します。だから私がする必要があると思ったのは、どういうわけか実際のタイプのメッセージを Forward メソッドに渡し、そのタイプが実際のタイプの応答になるようにすることです。
メソッドを次のように変更しました。
private void OnAsyncResponseReceived(Response response)
{
messageBinder.Forward((dynamic)response);
}
それは機能しますが、どういうわけか、これを行うためのより良い(?)方法があると思います...またはこれが実際の唯一の解決策ですか?全体的なデザインを変更する必要があるかもしれませんが、わかりません...この種の問題に初めて直面しましたが、これが思い付きました。
私は提案、批評家、そしてもちろん、可能な限り最善の解決策を受け入れます:)私の解決策とは異なり、より効率的である場合、これをどのように実装しますか? 助けてくれてありがとう!