简体   繁体   English

铸造MyClass <T> 到MyClass <object> C#

[英]Casting MyClass<T> to MyClass<object> C#

I have been having some trouble implementing an EventHandler in C# I can't seem to cast Action<T> to Action<object> for storage in a list. 我在用C#实现EventHandler时遇到了一些麻烦,我似乎无法将Action<T>Action<object>以便存储在列表中。

private readonly IList<Action<object>> listeners;

public EventHandler() {
    listeners = new List<Action<object>>();
}

public void RegisterListener<T>(Action<T> listener) where T : class {
        Listeners.Add((Action<object>)listener);
    }

private void ReciveEvent(object evt) {
       if (evt != null)
            Listeners.Where(l => l.GetGeneric(0).
            IsAssignableFrom(evt.GetType())).
            AsParallel().ForAll(l => l(evt));
     }

I just get a cast exception: 我只是得到一个强制转换异常:

Unable to cast object of type 'System.Action`1[Events.SendTestEvent]' to type 'System.Action`1[System.Object]'.

Events.SendTestEvent <- My current test object... it is just a class with a single property and no parent(besides obj)

An Action<object> is a method that can accept anything as it's parameter. Action<object>是一种可以接受任何内容作为其参数的方法。 An Action<T> is an object that can accept only an object of type T as its parameter. Action<T>是只能接受类型为T的对象作为其参数的对象 If you could treat an Action<T> as an Action<object> then you could pass an object that isn't of type T , but that action can't accept objects that aren't of type T , so the compiler prohibits you from doing this. 如果您可以将Action<T>视为Action<object>则可以传递非T类型的对象,但该动作不能接受非T类型的对象 ,因此编译器禁止您从这样做。

What you're trying to do is cast an Action<T> into an Action<object> , which isn't possible. 您要尝试将Action<T>转换为Action<object> ,这是不可能的。 You can make a new Action that triggers the action passed by the method and insert that into your list like this: 您可以创建一个新的Action来触发该方法传递的操作,然后将其插入列表中,如下所示:

public void RegisterListener<T>(Action<T> listener) where T : class 
{
    Action<object> wrappingAction = (arg)=>
    {
       var castArg = arg as T;
       if(castArg != null)
       {
           listener(castArg);
       }
    };

    Listeners.Add(wrappingAction);    
}

Note: This will only trigger the listeners if the object can be cast to the accepted parameter type, however, this is fairly inefficient (as you'd be casting for each listener listening for that type) 注意:仅当对象可以转换为可接受的参数类型时,这才会触发侦听器,但是,这效率很低(因为您将为侦听该类型的每个侦听器强制转换)

You can't do this because it wouldn't be safe. 您不能这样做,因为它不安全。 It would allow you to do 它会让你做

RegisterListener<string>(s => { Console.WriteLine(s); });
Action<object> a = listeners[0];
a(3);

You could wrap the given handler in one which casts to the target type on invocation eg 您可以将给定的处理程序包装成一个,在调用时强制转换为目标类型

public void RegisterListener<T>(Action<T> listener) where T : class {
    Listeners.Add(o => { listener((T)o); });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM