C# 是否可能对泛型方法进行不安全的协变调用?

C# 是否可能对泛型方法进行不安全的协变调用?,c#,generics,C#,Generics,我已经设计了许多类来处理特定类型的对象 e、 g 当然,我可以从处理程序接口中删除泛型。然而,我走这条路的原因是我想使处理程序的API尽可能简单。我希望类能够指定它们接收的消息,并且能够处理这些消息,而不必在每个方法中强制转换参数 如果可能的话,我更愿意避免反射,完全避免泛型似乎不太令人满意 我是否遗漏了一些明显的东西,或者我正在挑战C#的泛型的极限 我意识到C#不是Java(使用Java的类型擦除,这将很容易),也许用一种更类似C的方式解决这个问题会更好。。。所以我也对其他方法感兴趣 谢谢 您

我已经设计了许多类来处理特定类型的对象

e、 g

当然,我可以从处理程序接口中删除泛型。然而,我走这条路的原因是我想使处理程序的API尽可能简单。我希望类能够指定它们接收的消息,并且能够处理这些消息,而不必在每个方法中强制转换参数

如果可能的话,我更愿意避免反射,完全避免泛型似乎不太令人满意

我是否遗漏了一些明显的东西,或者我正在挑战C#的泛型的极限

我意识到C#不是Java(使用Java的类型擦除,这将很容易),也许用一种更类似C的方式解决这个问题会更好。。。所以我也对其他方法感兴趣


谢谢

您在使用反射方面有自己的解决方案:)

这是我所知道的唯一可以做到这一点的方法。我在ESB中使用的正是这种方法


编辑

在使用其他方法时有一个警告(我可能是错的,所以如果我偏离了轨道,请发表评论)。当您注册具有已知消息类型的“singleton”处理程序时,这是可以接受的。使用通用的
表示您知道类型。然而,在我的场景中,我根据到达的消息类型使用临时处理程序。所以我创建了一个新的处理程序

这意味着一切都必须在运行中完成,因此需要反射(除了在.NET4中使用
dynamic
——我在.NET3.5上)


想法?

我怀疑,如果你再进一步,动态键入会奏效:

void ProcessMessage(dynamic message) {
   dynamic handler = handlers[message.GetType()];
   handler.ProcessMessage(message);
}
请注意我是如何将
消息
动态化的,以便使用对象的实际类型而不是
对象
应用重载解析的

基本上,您试图做的不是静态类型安全的,这就是为什么C#编译器不让您逍遥法外的原因。这在执行时只有
类型
值的情况下非常典型

另一种选择是自己拥有一个通用方法,并通过反射或动态执行该方法:

void ProcessMessage(dynamic message)
{
    // This will call the generic method with the right
    // type for T inferred from the actual type of the object
    // message refers to.
    ProcessMessageImpl(message);
}

void ProcessMessageImpl<T>(T message)
{
    Handler<T> handler = (Handler<T>) handlers[typeof(T)];
    handler.ProcessMessage(message);
}
void进程消息(动态消息)
{
//这将调用具有右键的泛型方法
//根据对象的实际类型推断的T的类型
//消息指的是。
ProcessMessageImpl(消息);
}
void ProcessMessageImpl(T消息)
{
Handler=(Handler)Handler[typeof(T)];
ProcessMessage(message);
}

有更好的方法。只需将强制转换嵌入lambda并存储操作而不是处理程序:

    Dictionary<Type, Action<object>> handlers;

    void AddHandler<T>( Handler<T> handler )
    {
        handlers.Add(typeof(T), m => handler.ProcessMessage((T)m));
    }

    void ProcessMessage(object message)
    {
        var handler = handlers[message.GetType()];
        handler(message);
    }
字典处理程序;
void AddHandler(处理程序处理程序)
{
Add(typeof(T),m=>handler.ProcessMessage((T)m));
}
无效处理消息(对象消息)
{
var handler=handlers[message.GetType()];
处理程序(消息);
}
好的,这稍微超出了问题的范围,但是评论中的讨论让我们来到这里:

interface IMessage {}

class Foo : IMessage {}

interface Handler<T> where T : IMessage
{
    void ProcessMessage(T obj);
}

class FooHandler : Handler<Foo>
{
    public void ProcessMessage(Foo foo) {}
}

class Program
{
    static readonly Dictionary<Type, Action<object>> handlers = new Dictionary<Type, Action<object>>();

    static void AddHandler<T>(Handler<T> handler) where T : IMessage
    {
        handlers.Add(typeof(T), m => handler.ProcessMessage((T)m));
    }

    static void ProcessMessage(object message)
    {
        var handler = handlers[message.GetType()];
        handler(message);
    }

    public static IEnumerable<Type> GetAllTypes()
    {
        return AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes());
    }

    public static IEnumerable<Type> GetDerivedFrom<T>()
    {
        return GetAllTypes().Where(t => IsDerivedFrom(t, typeof(T)));
    }

    static bool IsDerivedFrom(Type t, Type parent)
    {
        return parent.IsAssignableFrom(t) && t!=parent;
    }

    static void Main()
    {
        var handlerTypes =
            from handlerBaseType in GetDerivedFrom<IMessage>().Select(t => typeof(Handler<>).MakeGenericType(t))
            select GetAllTypes().FirstOrDefault(t => IsDerivedFrom(t, handlerBaseType))
            into handlerType
            where handlerType!=null
            select Activator.CreateInstance(handlerType);

        foreach (object handler in handlerTypes)
        {
            AddHandler((dynamic)handler);
            Console.WriteLine("Registered {0}.", handler.GetType());
        }
    }
}
接口IMessage{}
类Foo:IMessage{}
接口处理程序,其中T:IMessage
{
无效处理消息(T obj);
}
类foodhandler:Handler
{
public void ProcessMessage(Foo Foo){}
}
班级计划
{
静态只读字典处理程序=新建字典();
静态void AddHandler(Handler Handler),其中T:IMessage
{
Add(typeof(T),m=>handler.ProcessMessage((T)m));
}
静态void ProcessMessage(对象消息)
{
var handler=handlers[message.GetType()];
处理程序(消息);
}
公共静态IEnumerable GetAllTypes()
{
返回AppDomain.CurrentDomain.GetAssemblys().SelectMany(a=>a.GetTypes());
}
公共静态IEnumerable GetDerivedFrom()
{
返回GetAllTypes(),其中(t=>isderivefrom(t,typeof(t));
}
静态布尔值IsDerivedFrom(t型,父型)
{
返回父项。IsAssignableFrom(t)&&t!=父项;
}
静态void Main()
{
变量句柄类型=
从GetDerivedFrom()中的handlerBaseType。选择(t=>typeof(Handler)。MakeGenericType(t))
选择GetAllTypes().FirstOrDefault(t=>IsDerivedFrom(t,handlerBaseType))
成手型
其中handlerType!=null
选择Activator.CreateInstance(handlerType);
foreach(handlerTypes中的对象处理程序)
{
AddHandler((动态)处理程序);
WriteLine(“注册的{0}.”,handler.GetType();
}
}
}

没有任何牵连。。。当然,如果您想通过命名来建立约定,您可以简化扫描,只需像在注释中那样从消息类型的名称中查找处理程序类型。您还可以用IOC容器替换Activator.CreateInstance。

我最终实现了Jon的想法,并在这里分享

public interface IHandler
{
    void ProcessMessage(dynamic message);
}

public class Handler<T> : IHandler
{
    public void ProcessMessage(dynamic message)
    {
    }
}

public class A{} public class B{} public class C{} public class D{}

public class HandlerA : IHandler{
    public void ProcessMessage(dynamic message){}
}

public class HandlerB  : IHandler{
    public void ProcessMessage(dynamic message) {}
}

public class HandlerC  : IHandler{
    public void ProcessMessage(dynamic message) {}
}

public class MsgProcessor
{
    public Dictionary<Type, IHandler> handlers = new Dictionary<Type, IHandler>();

    public void AddHandler<T>(T o) where T: IHandler
    {
        handlers.Add(typeof(T),o);
    }

    public void ProcessMessage(dynamic message)
    {
        ProcessMessage(message);
    }

    public void ProcessMessage<T>(T message)
    {
        Handler<T> handler = (Handler<T>) handlers[typeof (T)];
        handler.ProcessMessage(message);
    }
}

public class Test
{
    public void test()
    {
        var mp = new MsgProcessor();
        mp.AddHandler<HandlerA>(new HandlerA());
        mp.AddHandler<HandlerB>(new HandlerB());
        mp.AddHandler<HandlerC>(new HandlerC());

        mp.ProcessMessage(new A());
        mp.ProcessMessage(new B());
        mp.ProcessMessage(new C());

    }
}
公共接口IHandler
{
void ProcessMessage(动态消息);
}
公共类处理程序:IHandler
{
public void ProcessMessage(动态消息)
{
}
}
公共类A{}公共类B{}公共类C{}公共类D{}
公共类HandlerA:IHandler{
public void ProcessMessage(动态消息){}
}
公共类处理程序B:IHandler{
public void ProcessMessage(动态消息){}
}
公共类HandlerC:IHandler{
public void ProcessMessage(动态消息){}
}
公共类MsgProcessor
{
公共字典处理程序=新字典();
public void AddHandler(to),其中T:IHandler
{
添加(类型(T),o);
}
public void ProcessMessage(动态消息)
{
ProcessMessage(消息);
}
公共无效处理消息(T消息)
{
Handler=(Handler)Handler[typeof(T)];
ProcessMessage(message);
}
}
公开课考试
{
公共空间
void ProcessMessage(dynamic message) {
   dynamic handler = handlers[message.GetType()];
   handler.ProcessMessage(message);
}
void ProcessMessage(dynamic message)
{
    // This will call the generic method with the right
    // type for T inferred from the actual type of the object
    // message refers to.
    ProcessMessageImpl(message);
}

void ProcessMessageImpl<T>(T message)
{
    Handler<T> handler = (Handler<T>) handlers[typeof(T)];
    handler.ProcessMessage(message);
}
    Dictionary<Type, Action<object>> handlers;

    void AddHandler<T>( Handler<T> handler )
    {
        handlers.Add(typeof(T), m => handler.ProcessMessage((T)m));
    }

    void ProcessMessage(object message)
    {
        var handler = handlers[message.GetType()];
        handler(message);
    }
interface IMessage {}

class Foo : IMessage {}

interface Handler<T> where T : IMessage
{
    void ProcessMessage(T obj);
}

class FooHandler : Handler<Foo>
{
    public void ProcessMessage(Foo foo) {}
}

class Program
{
    static readonly Dictionary<Type, Action<object>> handlers = new Dictionary<Type, Action<object>>();

    static void AddHandler<T>(Handler<T> handler) where T : IMessage
    {
        handlers.Add(typeof(T), m => handler.ProcessMessage((T)m));
    }

    static void ProcessMessage(object message)
    {
        var handler = handlers[message.GetType()];
        handler(message);
    }

    public static IEnumerable<Type> GetAllTypes()
    {
        return AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes());
    }

    public static IEnumerable<Type> GetDerivedFrom<T>()
    {
        return GetAllTypes().Where(t => IsDerivedFrom(t, typeof(T)));
    }

    static bool IsDerivedFrom(Type t, Type parent)
    {
        return parent.IsAssignableFrom(t) && t!=parent;
    }

    static void Main()
    {
        var handlerTypes =
            from handlerBaseType in GetDerivedFrom<IMessage>().Select(t => typeof(Handler<>).MakeGenericType(t))
            select GetAllTypes().FirstOrDefault(t => IsDerivedFrom(t, handlerBaseType))
            into handlerType
            where handlerType!=null
            select Activator.CreateInstance(handlerType);

        foreach (object handler in handlerTypes)
        {
            AddHandler((dynamic)handler);
            Console.WriteLine("Registered {0}.", handler.GetType());
        }
    }
}
public interface IHandler
{
    void ProcessMessage(dynamic message);
}

public class Handler<T> : IHandler
{
    public void ProcessMessage(dynamic message)
    {
    }
}

public class A{} public class B{} public class C{} public class D{}

public class HandlerA : IHandler{
    public void ProcessMessage(dynamic message){}
}

public class HandlerB  : IHandler{
    public void ProcessMessage(dynamic message) {}
}

public class HandlerC  : IHandler{
    public void ProcessMessage(dynamic message) {}
}

public class MsgProcessor
{
    public Dictionary<Type, IHandler> handlers = new Dictionary<Type, IHandler>();

    public void AddHandler<T>(T o) where T: IHandler
    {
        handlers.Add(typeof(T),o);
    }

    public void ProcessMessage(dynamic message)
    {
        ProcessMessage(message);
    }

    public void ProcessMessage<T>(T message)
    {
        Handler<T> handler = (Handler<T>) handlers[typeof (T)];
        handler.ProcessMessage(message);
    }
}

public class Test
{
    public void test()
    {
        var mp = new MsgProcessor();
        mp.AddHandler<HandlerA>(new HandlerA());
        mp.AddHandler<HandlerB>(new HandlerB());
        mp.AddHandler<HandlerC>(new HandlerC());

        mp.ProcessMessage(new A());
        mp.ProcessMessage(new B());
        mp.ProcessMessage(new C());

    }
}