为什么这样:Interface <t>不是使用IS关键字比较的Interface <t>类型?

时间:2016-03-03 23:15:45

标签: c# generics

我想弄清楚为什么在我投射时使用is关键字似乎有所不同。这是一个显示我正在查看的测试用例:

[TestFixture]
public class TestMy {

    public interface IBaseMessage { }

    public interface IMessageProcessor<T> where T : IBaseMessage {
        void Process(T msg);
    }

    public class RRMessage : IBaseMessage {
    }

    public class BaseMessageProcessor {
        public bool CanProcess<T>(T msg) where T : IBaseMessage {
            return this is IMessageProcessor<T>;
        }
    }

    public class RRMessageProcessor : BaseMessageProcessor, IMessageProcessor<RRMessage> {
        public void Process(RRMessage msg) {
            throw new NotImplementedException();
        }
    }

    [Test]
    public void Test1() {
        var msgProcessor = new RRMessageProcessor();
        var msg = new RRMessage(); 
        Console.WriteLine(msgProcessor.CanProcess(msg));
    }

    [Test]
    public void Test2() {
        var msgProcessor = new RRMessageProcessor();
        var msg = new RRMessage() as IBaseMessage; 
        Console.WriteLine(msgProcessor.CanProcess(msg));
    }

为什么Test1()返回True而Test2()返回False。如何实施CanProcess()以便在两种情况下都返回True

1 个答案:

答案 0 :(得分:4)

Test1中的类型推断意味着它正在调用

msgProcessor.CanProcess<RRMessage>()

...而Test2正在调用

msgProcessor.CanProcess<IBaseMessage>()

现在RRMessageProcessor未实现IMessageProcessor<IBaseMessage> - 您无法调用Process(justAnyMessage) - 知道如何处理RRMessage值。所以这基本上是完全合理的。

要使两个测试都返回true,您实际上并不需要通用方法,因为您只关心msg执行时类型。这里有几个选项:

  • 使用私有泛型方法,但使用类型为dynamic的参数调用它,在这种情况下,将使用消息的执行时类型执行类型推断:

    public bool CanProcess(IBaseMessage message)
    {
        dynamic d = message;
        // Perform type inference at execution time
        return CanProcess(d);
    }
    
    private bool CanProcess<T>(T message)
    {
        return this is IMessageProcessor<T>;
    }
    
  • 使用反射检查界面,例如致电typeof(IMessageProcessor<>).MakeGenericType(msg.GetType()).IsAssignableFrom(GetType())

请注意,您仍然需要小心谨慎 - 假设您有一些来自SpecialRRMessage的{​​{1}} ...然后RRMessage仍然可以合理地处理它,但它不会实施RRMessageProcessor

您可能想要更改IMessageProcessor<SpecialRRMessage>界面,以便IMessageProcessor<T>被宣布为逆变

T

此时,由于违反,您的public interface IMessageProcessor<in T> where T : IBaseMessage 实施RRMessageProcessor