【问题标题】:How to cast an object into other interface如何将对象转换为其他接口
【发布时间】:2021-07-28 19:57:01
【问题描述】:

这是我的代码

IDevice接口用于声明类是MessageBus的设备。

public interface IDevice
{
    int ID{ get;}
}

ISubscriber<> 用于声明该类是订阅者并订阅了TMessage

public interface ISubscriber<TMessage> where TMessage : IMessage
{
    void Listen(TMessage message);
}

IMessage 用于声明消息。

public interface IMessage { }

这里定义了一条消息和订阅该消息的设备

public class TestMessage : IMessage { }

public class TestDevice : IDevice, ISubscriber<TestMessage>

问题来了,如何将TestDeviceIDevice 转换为ISubscriberList

public class MessageBus
{
    //key: Type of message
    public Dictionary<Type, List<ISubscriber<IMessage>>> SubscriberList { get; }

    //...

    public void Subscribe(IDevice device)
    {
        var deviceInfo = device.GetType();
        var isSubscriber = deviceInfo.GetInterfaces().Any(item => item.IsGenericType && 
        if (isSubscriber)
        {
            var subscriptionList = deviceInfo.GetInterfaces().Cast<Type>().ToList().FindAll(item => item.IsGenericType && item.GetGenericTypeDefinition() == typeof(ISubscriber<>));
            foreach (var subscription in subscriptionList)
            {
                var message = subscription.GenericTypeArguments.First();
                if (!SubscriberList.ContainsKey(message))
                {
                    SubscriberList.Add(message, new List<ISubscriber<IMessage>>());
                }
                //Here is the problem come from, how to cast the device from IDevice into ISubscriber<TestMessage> or ISubScriber<message>
                SubscriberList[message].Add(device);

            }

        }
    }

    //...
}

对不起,如果这是一个转储问题。

【问题讨论】:

  • 您不能将IDevice 投射到不相关的接口ISubscriber&lt;&gt;。这两个接口没有继承关系。不过,您可以将TestDevice 投射到任何接口。如果您希望所有设备都作为订阅者工作,您需要让 IDevice 继承自 ISubscriber
  • 那么有没有一种方法可以将IDevice 转换为它的真实类,比如这里的TestDevice
  • 真正的问题是,当你真正需要ISubscriber&lt;IMessage&gt; 时,为什么还要使用IDevice?如果您希望IDevice 成为ISubscriber,为什么不让它从ISubscriber 继承?
  • 我希望有其他接口,如IClient,设备可以是IClient,但不是ISubscriber
  • 如果您将 ISubscriber 更改为 public interface ISubscriber&lt;out TMessage&gt; where TMessage : IMessage { void Listen(IMessage message); },您将能够将 TestDevice 分配或传递给任何期望 ISubscriber&lt;IMessage&gt; 的变量或参数。如果你试图将一个接口转换为一个不相关的接口,那你就错了

标签: c# .net interface casting


【解决方案1】:

您可以使用is检查类型和转换对象:

if(device is ISubscriber<TestMessage> subscriber){
     // Use subscriber
}

但是,在使用这些类型的模式时,您应该非常小心,因为它很容易导致方法的行为根据给定对象的类型而有所不同。如果唯一的变化是更好的性能,那可能没问题,但这里似乎并非如此。

在这种情况下,最好采用两个单独的参数,一个用于设备,一个用于订阅者。这可能是同一个对象,但该方法不应该关心这一点。您还可以创建一个继承自两者的IDeviceSubscriber 接口。

您还应该小心使用泛型ISubscriber&lt;TestMessage&gt; 是与ISubscriber&lt;TMessage&gt; 完全不同的类型。如果它们是variant,一个可能可以转换为另一个,但是使用 co/contra 方差有很多规则。

在不了解问题领域的情况下,很难提供更具体的建议。

【讨论】:

    猜你喜欢
    • 2020-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-07
    • 2012-01-16
    • 1970-01-01
    • 1970-01-01
    • 2021-12-22
    相关资源
    最近更新 更多