【问题标题】:Disable casting to explicit runtime type禁用转换为显式运行时类型
【发布时间】:2020-04-27 11:53:39
【问题描述】:

我想将对象作为接口类型传递,并禁用将对象转换为其运行时类型的选项。因此,当对象被传递给其他实体时,只允许在接口中声明的方法。

最后的动机。

我的例子有更进一步的解释:

class Program
{
    private interface Interface1
    {
        public void InterfaceAction();
    }

    private class Class1 : Interface1
    {
        public void InterfaceAction()
        {
            Console.WriteLine("Interface action");
        }

        public void ClassAction()
        {
            Console.WriteLine("Class action");
        }
    }

    private class Class2
    {
        public void UseTheInterface(Interface1 interfaceObject)
        {
            // At the context of Class2 execution, from the signature of the method I only know that 
            //      received object is of Interface1, thus I can only use its method "InterfaceAction"
            interfaceObject.InterfaceAction();

            // As the runtime type of "interfaceObject" is Class1, I can cast to it
            Class1 casted = (Class1) interfaceObject;

            // Now after I revealed the object real type, I can use its unique method "ClassAction"
            casted.ClassAction();
        }
    }

    static void Main(string[] args)
    {
        Class1 obj1 = new Class1();
        Class2 obj2 = new Class2();

        // Here an auto cast to Interface1 is made on obj1
        obj2.UseTheInterface(obj1);

        // Actual output:
        //      Interface action
        //      Class action

        // Wanted output:
        //      Interface action
        //      Cast exception at line 35
    }
}

我知道,一般来说,转换不应该失败,因为它实际上是对象的运行时类型。 但是,我想在将对象从一个类传递到另一个类时实现一种安全的使用方式。

假设我想将一个对象传递给某个类,并通过使用接口仅显示其部分方法,如上所示。我不想依赖其他类来正确使用它并单独使用接口方法,我想确保它不能访问除了接口中的方法之外的任何其他方法。

假设另一个类接受接口作为函数的参数,它只知道它声明的类型,因此不应该尝试强制转换。但是,另一个类可以简单地尝试对每个“Interface1”实现者进行暴力强制转换,直到找到合适的类型。 此外,还可以使用 .GetType() 扩展方法获取运行时类型,然后使用 switch 条件进行强制转换。

感谢您的帮助。

【问题讨论】:

  • 您应该实现接口internal,这样该类型就不能在实现程序集之外使用。也无法阻止采用反射方式并使用GetType() 起点。
  • 我确实想在程序集之外使用这种类型。我只是不希望任何获得 Interface1 的人都能够将其转换为 Class1,以防运行时类型实际上是 Class1。
  • 如果你不想要下面提到的包装器,没有办法阻止这种情况。

标签: c# casting


【解决方案1】:

我认为这是您可能使用包装器的情况。包装器将实现该接口,并具有对其将在其实现中调用的实际对象的内部引用。然后强制转换接口只会让你得到包装器。

例子

class Program
{
    private interface Interface1
    {
        void InterfaceAction();
    }

    private class Class1ToInterface1 : Interface1
    {
        Class1 wrapped;
        public Class1ToInterface1(Class1 wrapped)
        {
            this.wrapped = wrapped;
        }

        public void InterfaceAction()
        {
            wrapped.InterfaceAction();
        }
    }

    private class Class1 : Interface1
    {
        public void InterfaceAction()
        {
            Console.WriteLine("Interface action");
        }

        public void ClassAction()
        {
            Console.WriteLine("Class action");
        }
    }

    private class Class2
    {
        public void UseTheInterface(Interface1 interfaceObject)
        {
            // At the context of Class2 execution, from the signature of the method I only know that 
            //      received object is of Interface1, thus I can only use its method "InterfaceAction"
            interfaceObject.InterfaceAction();

            // As the runtime type of "interfaceObject" is Class1, I can cast to it
            Class1 casted = (Class1)interfaceObject; // InvalidCastException

            // Now after I revealed the object real type, I can use its unique method "ClassAction"
            casted.ClassAction(); // Won't get this far
        }
    }

    static void Main(string[] args)
    {
        Class1 obj1 = new Class1();
        Class2 obj2 = new Class2();
        Interface1 interfaceToObj1 = new Class1ToInterface1(obj1);

        // Here an auto cast to Interface1 is made on obj1
        obj2.UseTheInterface(interfaceToObj1);

        // Actual output:
        //      Interface action
        //      Class action

        // Wanted output:
        //      Interface action
        //      Cast exception at line 35
    }
}

这应该生成一个System.InvalidCastException“无法将'Class1ToInterface1'类型的对象转换为'Class1'类型。”上线就行:

Class1 casted = (Class1)interfaceObject; // InvalidCastException

【讨论】:

  • 您的回答基本上是使用适配器。但是,我不想更改正在使用的运行时类型,只是为了防止对其进行强制转换。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-03
  • 2010-10-11
相关资源
最近更新 更多