C# “的顺序问题”;“注册”;消息传递场景中.NET类的数量
我看到这个问题经常出现,但从来没有得到充分的处理,而且我还没有在堆栈溢出上看到它,所以现在开始。我希望有一种方法可以简明扼要地表达这一点而不缺乏清晰度,但我似乎不能缩短它,所以请容忍我 下面是一个很好的案例研究(当然是我目前的案例)来说明这个问题: 我为许多位置、一个父比较(parentco)和几个卫星位置(centers)编写代码。我有两个“经理”,一个是为家长公司设计的,另一个是为中心设计的(部署了很多次)。我还有两个库,一个用于中心,一个通用库(用于中心和parentco),程序可以包括这两个库,以便与相应的管理员通信(通过TCP)。中心库中有几个类设计用于包装数据库表和其他“消息”以完成其他任务,而通用库中也有一些“消息”,如“结束连接”、“调用进程”等 问题: 当管理器接收到在“通用”库中定义的消息时,它如何知道它是哪种类型的消息?第一个解决方案是这样的:C# “的顺序问题”;“注册”;消息传递场景中.NET类的数量,c#,class,static,constructor,registration,C#,Class,Static,Constructor,Registration,我看到这个问题经常出现,但从来没有得到充分的处理,而且我还没有在堆栈溢出上看到它,所以现在开始。我希望有一种方法可以简明扼要地表达这一点而不缺乏清晰度,但我似乎不能缩短它,所以请容忍我 下面是一个很好的案例研究(当然是我目前的案例)来说明这个问题: 我为许多位置、一个父比较(parentco)和几个卫星位置(centers)编写代码。我有两个“经理”,一个是为家长公司设计的,另一个是为中心设计的(部署了很多次)。我还有两个库,一个用于中心,一个通用库(用于中心和parentco),程序可以包括这
namespace generic_library
{
public interface IMessage_Creator
{
public IMessage Create_Message(short id);
}
public interface IMessage
{
short Message_ID { get; }
}
/// <summary>Perhaps a message to kill the current connection</summary>
public class Generic_Message1 : IMessage
{
public short Message_ID { get { return ID; } }
internal const short ID = 1;
}
public static class Message_Handler
{
private static readonly System.Collections.Generic.List<IMessage_Creator> _creators =
new System.Collections.Generic.List<IMessage_Creator>();
public static void Add_Creator(IMessage_Creator creator)
{
_creators.Add(creator);
}
public static IMessage Get_Message(short id)
{
switch (id)
{//the Generic library knows about the generic messages...
case Generic_Message1.ID:
return new Generic_Message1();
}
//no generic message found, search the registered creators.
IMessage ret = null;
foreach (IMessage_Creator creator in _creators)
{
ret = creator.Create_Message(id);
if (ret != null)
{
return ret;
}
}
//null if no creator was found.
return ret;
}
}
}
namespace center
{
public class Center_Creator : generic_library.IMessage_Creator
{
static Center_Creator()
{
generic_library.Message_Handler.Add_Creator(new Center_Creator());
}
public generic_library.IMessage Create_Message(short id)
{
switch (id)
{//The center library knows about center-specific messages
case center_message1.ID:
return new center_message1();
}
//we return null to say, "I don't know about that message id."
return null;
}
}
public class center_message1 : generic_library.IMessage
{
public short Message_ID
{
get { return ID; }
}
internal const short ID = 2;
}
}
命名空间通用库
{
公共接口IMessage_创建者
{
公共IMessage创建_消息(短id);
}
公共接口IMessage
{
短消息_ID{get;}
}
///可能是要终止当前连接的消息
公共类通用消息1:IMessage
{
公共短消息{u ID{get{return ID;}}
内部常量短ID=1;
}
公共静态类消息\u处理程序
{
私有静态只读System.Collections.Generic.List\u创建者=
新建System.Collections.Generic.List();
公共静态无效添加创建者(IMessage创建者)
{
_creators.Add(creator);
}
公共静态IMessage Get_消息(短id)
{
开关(id)
{//泛型库知道有关泛型消息的信息。。。
案例通用消息1.ID:
返回新的泛型消息1();
}
//未找到一般消息,请搜索已注册的创建者。
IMessage ret=null;
foreach(IMessage_Creator in_creators)
{
ret=创建者。创建消息(id);
如果(ret!=null)
{
返回ret;
}
}
//如果未找到创建者,则为null。
返回ret;
}
}
}
名称空间中心
{
公共类中心_创建者:generic_library.IMessage_创建者
{
静态中心创建器()
{
generic_library.Message_Handler.Add_Creator(new Center_Creator());
}
公共通用_library.IMessage创建_消息(短id)
{
开关(id)
{//中心库知道中心特定的消息
案例中心消息1.ID:
返回新的中心消息1();
}
//我们返回null表示,“我不知道该消息id。”
返回null;
}
}
公共类中心_消息1:generic_library.IMessage
{
公共短消息\u ID
{
获取{return ID;}
}
内部常量短ID=2;
}
}
一点解释。如您所见,中心和通用库都有自己的消息可以处理。中心接口(此处由名称空间中心
表示)在静态构造函数中注册其创建者中心创建者
,因此当消息处理程序
获取其类型的消息时,将调用创建者生成正确的消息
这种方法的问题:
您可能已经看到了这里的问题,即:
如果代码从未访问过类中心创建者(从未创建过一个,也从未调用过静态方法),则在收到该类型的消息之前,应该是这样,静态构造函数,static Center\u Creator()
,因此message\u Handler
永远不知道该创建者
这一切都很好,但我不知道如何修复它。许多人建议使用反射来调用Center\u Creator
类型初始值设定项
,但我不想让每个使用此库的程序都承担这个负担
堆栈溢出社区的建议是什么?请让我知道我是否可以简化此过程,以帮助社区更容易访问
编辑:
代码用于通用库和中心库。如您所见,我在母公司库中也会遇到同样的问题
.让我们来详细分析一下:
- 您有一个用于发送和接收特定类型消息的应用程序
- 但是,必须先注册消息类型,然后才能读取它
- 在发送消息之前,您不会注册该类型,但是
- 您希望在编写消息之前能够阅读消息
Init()
方法。这可以通过使用反射扫描库来查看是否定义了类型,或者手动列出它们来实现。一些想法:
- 使用.NET序列化来序列化/反序列化消息,并将它们放入两端使用的类库中(甚至使用WCF来处理通信)
- 在第一次调用Get_消息(“if(!initialized)FindAddCreators()”)时,向creator类添加自定义属性,并使用反射填充creator列表;
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; namespace SO { class Program { static void Main(string[] args) { MessageFactory factory = new MessageFactory(); IMessage msg = factory.CreateObject(1); IMessage msg2 = factory.CreateObject(2); } } public interface IMessage { short Message_ID { get; } } public class Generic_Message1 : IMessage { public short Message_ID { get { return ID; } } internal const short ID = 1; } public class center_message1 : IMessage { public short Message_ID { get { return ID; } } internal const short ID = 2; } public class MessageFactory { private Dictionary<short, Type> messageMap = new Dictionary<short, Type>(); public MessageFactory() { Type[] messageTypes = Assembly.GetAssembly(typeof(IMessage)).GetTypes(); foreach (Type messageType in messageTypes) { if (!typeof(IMessage).IsAssignableFrom(messageType) || messageType == typeof(IMessage)) { // messageType is not derived from IMessage continue; } IMessage message = (IMessage)Activator.CreateInstance(messageType); messageMap.Add(message.Message_ID, messageType); } } public IMessage CreateObject(short Message_ID, params object[] args) { return (IMessage)Activator.CreateInstance(messageMap[Message_ID], args); } } }
// Read customMessageDllName and customMessageClassName from your config file Assembly assembly = Assembly.Load(customMessageDllName); IMessage customMessage = (IMessage)assembly.CreateInstance(customMessageClassName);
using System; using System.Collections.Generic; using System.ComponentModel.Composition; using System.ComponentModel.Composition.Hosting; namespace Playground { public class Program { static void Main(string[] args) { PluginHost host = new PluginHost(); host.PrintListOfPlugins(); Console.ReadKey(); } } public class PluginHost { [ImportMany] public IEnumerable<IPlugin> Plugins { get; set; } public PluginHost() { var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()); var container = new CompositionContainer(catalog); container.ComposeParts(this); } public void PrintListOfPlugins() { foreach (IPlugin plugin in Plugins) Console.WriteLine(plugin.Description); } } public interface IPlugin { string Description { get; } } [Export(typeof(IPlugin))] public class ExamplePlugin : IPlugin { #region IPlugin Members public string Description { get { return "I'm an example plugin!"; } } #endregion } }
Generic_lib.IMessage msg = Generic_lib.Message_Handler.get_message(2); //a Center Message if (msg is Center_lib.Center_Message) { System.Console.WriteLine("got center message"); }
static Message_Handler() { //here, do the registration. int registered = 0; System.Reflection.Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies(); foreach (System.Reflection.Assembly asm in assemblies) { System.Type[] types = asm.GetTypes(); foreach (System.Type t in types) { System.Type[] interfaces = t.GetInterfaces(); foreach (System.Type i in interfaces) { if (i == typeof(IMessage_Creator)) { System.Reflection.ConstructorInfo[] constructors = t.GetConstructors(); foreach (System.Reflection.ConstructorInfo ctor in constructors) { if (ctor.GetParameters().Length == 0) { Add_Creator(ctor.Invoke(new object[0]) as IMessage_Creator); registered++; } } } } } } System.Diagnostics.Debug.WriteLine("registered " + registered.ToString() + " message creators."); }
if (msg is Center_lib.Center_Message) ;