如何使用逆变参数将通用接口转换为基本类型?

我试图开发一个通用的命令处理器。 我想创建实现给定接口的命令处理程序类。 我将使用控制反转来根据收到的命令类型创建适当类的实例。 然后我想以通用的方式调用该类的“Execute”方法。

我能够使用协变类型参数进行这项工作,但在这种情况下,我不能使用泛型类型参数作为方法参数。

似乎反变法应该可行,因为它允许我根据需要声明方法参数,但不幸的是,该类的实例不能转换为基接口。

下面的代码举例说明了这个问题:

using System;
using System.Diagnostics;

namespace ConsoleApplication2
{
    // Command classes

    public class CommandMessage
    {
        public DateTime IssuedAt { get; set; }
    }

    public class CreateOrderMessage : CommandMessage
    {
        public string CustomerName { get; set; }
    }

    // Covariant solution

    public interface ICommandMessageHandler1<out T> where T : CommandMessage
    {
        void Execute(CommandMessage command);
    }

    public class CreateOrderHandler1 : ICommandMessageHandler1<CreateOrderMessage>
    {
        public void Execute(CommandMessage command)
        {
            // An explicit typecast is required
            var createOrderMessage = (CreateOrderMessage) command;
            Debug.WriteLine("CustomerName: " + createOrderMessage.CustomerName);
        }
    }

    // Contravariant attempt (doesn't work)

    public interface ICommandMessageHandler2<in T> where T : CommandMessage
    {
        void Execute(T command);
    }

    public class CreateOrderHandler2 : ICommandMessageHandler2<CreateOrderMessage>
    {
        public void Execute(CreateOrderMessage command)
        {
            // Ideally, no typecast would be required
            Debug.WriteLine("CustomerName: " + command.CustomerName);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var message = new CreateOrderMessage {CustomerName = "ACME"};

            // This code works
            var handler1 = new CreateOrderHandler1();
            ICommandMessageHandler1<CreateOrderMessage> handler1b = handler1;
            var handler1c = (ICommandMessageHandler1<CommandMessage>) handler1;
            handler1c.Execute(message);

            // This code throws InvalidCastException
            var handler2 = new CreateOrderHandler2();
            ICommandMessageHandler2<CreateOrderMessage> handler2b = handler2;
            var handler2c = (ICommandMessageHandler2<CommandMessage>)handler2;  // throws InvalidCastException
            handler2c.Execute(message);
        }
    }
}

您可以铸有通用接口out泛型参数只能用更具体的参数的接口。 例如, ICommandMessageHandler1<CommandMessage>可以被转换为ICommandMessageHandler2<CreateOrderMessage>Execute(CommandMessage command)也将接受CreateOrderMessage ),但反之亦然。

试着想一下,例如,如果在你的代码中抛出一个InvalidCastException将被允许​​,如果你调用了handler2c.Execute(new CommandMessage())会发生什么?


接口ICommandMessageHandler1<T>ICommandMessageHandler2<T>彼此不相关。 仅仅因为两者都有一个方法Execute不会使它们兼容。 这将是duck-typing,这在c#中不受支持。


也许我并没有真正明白你想做什么,但是对于我来说没有任何类型转换,这很好。

public class CommandMessage
{
    public DateTime IssuedAt
    {
        get;
        set;
    }
}

public class CreateOrderMessage : CommandMessage
{
    public string CustomerName
    {
        get;
        set;
    }
}

public interface ICommandMessageHandler2<in T> where T : CommandMessage
{
    void Execute(T command);
}
public class CreateOrderHandler2 : ICommandMessageHandler2<CreateOrderMessage>
{
    public void Execute(CreateOrderMessage command)
    {
        // No typecast is required
        Debug.WriteLine("CustomerName: " + command.CustomerName);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var message = new CreateOrderMessage
        {
            CustomerName = "ACME"
        };

        // This code throws InvalidCastException
        var handler2 = (ICommandMessageHandler2<CreateOrderMessage>)new CreateOrderHandler2();
        handler2.Execute(message);
    }
}
链接地址: http://www.djcxy.com/p/39437.html

上一篇: How to cast generic interfaces using contravariant parameters to a base type?

下一篇: C#: combine DllImport with inheritance?