我有一个字典来将某种类型映射到该类型的某个通用对象.例如:
typeof(LoginMessage) maps to MessageProcessor<LoginMessage>
Run Code Online (Sandbox Code Playgroud)
现在问题是在运行时从Dictionary中检索这个通用对象.或者更具体:将检索到的对象强制转换为特定的泛型类型.
我需要它来做这样的事情:
Type key = message.GetType();
MessageProcessor<key> processor = messageProcessors[key] as MessageProcessor<key>;
Run Code Online (Sandbox Code Playgroud)
希望有一个简单的解决方案.
编辑:我不想使用Ifs和开关.由于性能问题,我也不能使用某种反射.
Jer*_*ink 30
这对你有用吗?
interface IMessage
{
void Process(object source);
}
class LoginMessage : IMessage
{
public void Process(object source)
{
}
}
abstract class MessageProcessor
{
public abstract void ProcessMessage(object source, object type);
}
class MessageProcessor<T> : MessageProcessor where T: IMessage
{
public override void ProcessMessage(object source, object o)
{
if (!(o is T)) {
throw new NotImplementedException();
}
ProcessMessage(source, (T)o);
}
public void ProcessMessage(object source, T type)
{
type.Process(source);
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<Type, MessageProcessor> messageProcessors = new Dictionary<Type, MessageProcessor>();
messageProcessors.Add(typeof(string), new MessageProcessor<LoginMessage>());
LoginMessage message = new LoginMessage();
Type key = message.GetType();
MessageProcessor processor = messageProcessors[key];
object source = null;
processor.ProcessMessage(source, message);
}
}
Run Code Online (Sandbox Code Playgroud)
这为您提供了正确的对象.我唯一不确定的是你的情况是否足以将它作为一个抽象的MessageProcessor.
编辑:我添加了一个IMessage界面.现在,实际的处理代码应成为应该实现此接口的不同消息类的一部分.
ptr*_*trc 23
以下似乎也有效,它比其他答案稍微短一些:
T result = (T)Convert.ChangeType(otherTypeObject, typeof(T));
Run Code Online (Sandbox Code Playgroud)
Type type = typeof(MessageProcessor<>).MakeGenericType(key);
Run Code Online (Sandbox Code Playgroud)
这是你能做的最好的事情,但是如果不知道它是什么类型的话,你真的可以用它来做更多的事情.
编辑:我应该澄清.我从var类型更改为Type类型.我的观点是,现在你可以这样做:
object obj = Activator.CreateInstance(type);
Run Code Online (Sandbox Code Playgroud)
OBJ现在将正确的类型,但是因为你不知道什么类型的"钥匙"是在编译的时候,有没有办法施展它,做任何有用的事情.
您可以编写一个将类型作为泛型参数的方法:
void GenericProcessMessage<T>(T message)
{
MessageProcessor<T> processor = messageProcessors[typeof(T)]
as MessageProcessor<T>;
// Call method processor or whatever you need to do
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要一种方法来使用正确的泛型参数调用该方法.你可以用反射做到这一点:
public void ProcessMessage(object message)
{
Type messageType = message.GetType();
MethodInfo method = this.GetType().GetMethod("GenericProcessMessage");
MethodInfo closedMethod = method.MakeGenericMethod(messageType);
closedMethod.Invoke(this, new object[] {message});
}
Run Code Online (Sandbox Code Playgroud)
我遇到了类似的问题.我上课了;
Action<T>
Run Code Online (Sandbox Code Playgroud)
它具有T型属性
当我不知道T时如何获得财产?除非我知道T,否则我无法投射到Action <>
解:
实现非通用接口;
public interface IGetGenericTypeInstance
{
object GenericTypeInstance();
}
Run Code Online (Sandbox Code Playgroud)
现在我可以将对象强制转换为IGetGenericTypeInstance,GenericTypeInstance将该属性作为类型对象返回.
小智 5
请查看以下解决方案是否适合您.诀窍是定义一个基本处理器接口,它接受基本类型的消息.
interface IMessage
{
}
class LoginMessage : IMessage
{
}
class LogoutMessage : IMessage
{
}
class UnknownMessage : IMessage
{
}
interface IMessageProcessor
{
void PrcessMessageBase(IMessage msg);
}
abstract class MessageProcessor<T> : IMessageProcessor where T : IMessage
{
public void PrcessMessageBase(IMessage msg)
{
ProcessMessage((T)msg);
}
public abstract void ProcessMessage(T msg);
}
class LoginMessageProcessor : MessageProcessor<LoginMessage>
{
public override void ProcessMessage(LoginMessage msg)
{
System.Console.WriteLine("Handled by LoginMsgProcessor");
}
}
class LogoutMessageProcessor : MessageProcessor<LogoutMessage>
{
public override void ProcessMessage(LogoutMessage msg)
{
System.Console.WriteLine("Handled by LogoutMsgProcessor");
}
}
class MessageProcessorTest
{
/// <summary>
/// IMessage Type and the IMessageProcessor which would process that type.
/// It can be further optimized by keeping IMessage type hashcode
/// </summary>
private Dictionary<Type, IMessageProcessor> msgProcessors =
new Dictionary<Type, IMessageProcessor>();
bool processorsLoaded = false;
public void EnsureProcessorsLoaded()
{
if(!processorsLoaded)
{
var processors =
from processorType in Assembly.GetExecutingAssembly().GetTypes()
where processorType.IsClass && !processorType.IsAbstract &&
processorType.GetInterface(typeof(IMessageProcessor).Name) != null
select Activator.CreateInstance(processorType);
foreach (IMessageProcessor msgProcessor in processors)
{
MethodInfo processMethod = msgProcessor.GetType().GetMethod("ProcessMessage");
msgProcessors.Add(processMethod.GetParameters()[0].ParameterType, msgProcessor);
}
processorsLoaded = true;
}
}
public void ProcessMessages()
{
List<IMessage> msgList = new List<IMessage>();
msgList.Add(new LoginMessage());
msgList.Add(new LogoutMessage());
msgList.Add(new UnknownMessage());
foreach (IMessage msg in msgList)
{
ProcessMessage(msg);
}
}
public void ProcessMessage(IMessage msg)
{
EnsureProcessorsLoaded();
IMessageProcessor msgProcessor = null;
if(msgProcessors.TryGetValue(msg.GetType(), out msgProcessor))
{
msgProcessor.PrcessMessageBase(msg);
}
else
{
System.Console.WriteLine("Processor not found");
}
}
public static void Test()
{
new MessageProcessorTest().ProcessMessages();
}
}
Run Code Online (Sandbox Code Playgroud)