【问题标题】:Cast to not explicitly implemented interface?转换为未明确实现的接口?
【发布时间】:2018-04-14 01:48:04
【问题描述】:

假设您定义了一些任意接口:

public interface IInterface {
    void SomeMethod();
}

假设有一些类碰巧有一个匹配的公共接口,即使它们没有“实现IInterface”。即:

public class SomeClass {
    public void SomeMethod() {
       // some code
    }
}

还有没有办法让IInterface 引用SomeClass 实例?即:

SomeClass myInstance = new SomeClass();
IInterface myInterfaceReference = (IInterface)myInstance;

【问题讨论】:

    标签: c#


    【解决方案1】:

    不,没有办法做到这一点。如果该类型没有实现接口,那么就无法转换为它。实现类似于您想要的行为的最佳方法是创建一个包装器类型,它为SomeClass 提供IInterface 的实现。

    public static class Extensions {
      private sealed class SomeClassWrapper : IInterface {
        private readonly SomeClass _someClass;
    
        internal SomeClassWrapper(SomeClass someClass) {
          _someClass = someClass;
        }
    
        public void SomeMethod() {
          _someClass.SomeMethod();
        }
      }
    
      public static IInterface AsIInterface(this SomeClass someClass) {
        return new SomeClassWrapper(someClass);
      }
    }
    

    然后你就可以拨打下面的电话了

    SomeClass myInstance = new SomeClass();
    IInterface myInterface = myInstance.AsIInterface();
    

    【讨论】:

    • 也可以使用反射在任何类的包装器中找到方法(如果没有找到则抛出异常)
    • 但是你如何“取消”它呢?还是把它扔回去?包装器失去了所有连接。
    • 如果运行时知道一个对象支持完全相同公共方法/属性,那么这个功能不存在真是太可惜了可以证明接口转换为具有那些完全相同公共方法/属性的接口。
    【解决方案2】:

    如果你可以访问源代码,你总是可以装饰类,如果没有,你可以做一个包装器:

    public class InterfaceWrapper : IInterface
    {
        private readonly SomeClass _someClass;
    
        public InterfaceWrapper(SomeClass someClass) { _someClass = someClass; }
    
        public void SomeMethod() { _someClass.SomeMethod(); }
    }
    

    【讨论】:

    • 如果我继承类如果它不是密封的并且实现保持继承类为空的接口,它会起作用
    【解决方案3】:

    CSScriptLibrary.dll 有一个扩展方法,可以将对象实例“对齐”到给定接口:

    public static T AlignToInterface<T>(this object obj) where T : class;
    

    同时检查库的其余部分,它在反射 C# 脚本时是一个非常有用的 API。

    最好的问候。

    【讨论】:

      【解决方案4】:

      没有。仅仅因为两个类碰巧有同名的方法并不意味着它们遵守相同的约定。这就是您通过显式实现适当的接口来定义合同的原因。

      【讨论】:

        【解决方案5】:

        SomeClass 实现的方法可能与接口中的签名相同,但由于它没有继承/实现接口,因此在这种情况下无法使用强制转换——不存在“意外”一致性 - 您必须明确声明它实现特定接口的每个类。

        【讨论】:

          【解决方案6】:

          现在dynamic 可以做到这一点。这与获取强类型引用不同,因为这是不可能的,但是如果它们碰巧具有具有相同签名的成员,您仍然可以将其他不相关的类型视为相同。

          void DoSomethingThatCallsSomeMethodOnEitherType(dynamic pObject) =>
             pObject.SomeMethod();
          
          SomeClass myInstance = new SomeClass();
          IInterface myInterface = GetAnIInterfaceFromSomewhere();
          
          DoSomethingThatCallsSomeMethodOnEitherType(myInstance);
          DoSomethingThatCallsSomeMethodOnEitherType(myInterface);
          

          一个具体的例子是ListControlBeginUpdate/EndUpdate 方法。这些方法是为具体类型定义的,而不是在基本类型上定义的。使用dynamic,无论您使用的是ComboBoxListBox,还是CheckedListBox,您仍然可以在不知道您使用的是哪一个的情况下调用BeginUpdate

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-02-23
            • 2019-07-31
            • 2019-07-26
            • 1970-01-01
            • 1970-01-01
            • 2015-04-11
            • 2016-07-09
            相关资源
            最近更新 更多