防止两个接口之间的转换 [英] Prevent Cast Between Two Interfaces

查看:56
本文介绍了防止两个接口之间的转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个内部类,其中包含实现细节,包括属性,不应公开访问.我必须将此类传递给公共调用者,并允许他们传递,存储,序列化它,或者基本上对其进行任何操作.可以通过两种不同的方式公开访问该类.这些方式公开为两个公共接口.我想防止用户在两个公共接口之间进行转换.这是一些代码来演示我在说什么.

I have an internal class which contains implementation details, including properties, which should not be publicly accessible. I have to pass this class to public callers, and allow them to pass it around, store it, serialize it, or do basically whatever they want with it. The class can be accessed publicly in two different ways. These ways are exposed as two public interfaces. I would like to prevent the user from casting between the two public interfaces. Here is some code to demonstrate what I am talking about.

void Main()
{
    var container = new ContainsDetails(5);

    Console.WriteLine(container.LessDetail.TheDetails);
    var more = (ContainsDetails.IFooPlus)(container.LessDetail);
    more.TheDetails = 10;
    Console.WriteLine(container.LessDetail.TheDetails);
}

public class ContainsDetails {
    public interface IFooPlus {
        int TheDetails {
            get;
            set;
        }
    }

    public interface IFoo {
        int TheDetails {
            get;
        }
    }

    private readonly Detail _myDetail;

    public ContainsDetails(int x) {
        _myDetail = new Detail(x);
    }

    public IFoo LessDetail {
        get {
            return _myDetail;
        }
    }

    public IFooPlus MoreDetail {
        get {
            return _myDetail;
        }
    }

    public bool ProcessFoo(IFoo foo) {
        var theDeets = foo as Detail;
        if (theDeets != null) {
            return theDeets.TheDetails++%2 == 0;
        } else {
            throw new ArgumentException("foo argument must have originated from ContainsDetails.");
        }
    }

    private class Detail : IFooPlus, IFoo {
        private int _myX;

        private Detail() {}

        internal Detail(int x) {
            _myX = x;
        }

        public int TheDetails {
            get {return  _myX; }
            set { _myX = value; }
        }
    }
}

输出为:

5
10

我希望上面的输出是:

5
System.InvalidCastException thrown.....

ContainsDetails 仅用于演示.在我的实际代码中,程序集扮演了 ContainsDetails 的角色.同样, Detail 是我实际代码中的 internal 类.

The class ContainsDetails is just present for demonstration. In my actual code the assembly fills the role of ContainsDetails. Similarly, Detail is an internal class in my actual code.

用户在此同时了解 IFooPlus IFoo .用户不知道 Detail 存在.用户也不知道 LessDetail 返回的对象是否可以转换为 IFooPlus .我的代码在不同的时间向用户返回了相同的 Detail 对象,并将根据<复杂的状态 Detail 和其他内部对象.还要注意 ContainsDetails 中的 ProcessFoo 方法.我的代码需要能够接受用户的 IFoo ,并将其作为 Detail 处理.

Here the user knows about both IFooPlus and IFoo. The user does not know that Detail exists. The user also does not know that the object returned by LessDetail is convertible to an IFooPlus. My code returns the same Detail object to the user at different times, and will return it as IFoo or IFooPlus depending on some complicated state of Detail and other internal objects. Also note the ProcessFoo method in ContainsDetails. My code needs to be able to accept an IFoo from the user, and process it as a Detail.

我想要强制转换 var more =(ContainsDetails.IFooPlus)(container.LessDetail)来生成 InvalidCastException .对所有 IFooPlus 操作进行运行时检查以确定 Detail 对象是否处于针对这些操作的正确状态,这是非常昂贵的.相反,我希望用户永远不能将 IFoo 视为 IFooPlus .

I would like for the cast var more = (ContainsDetails.IFooPlus)(container.LessDetail) to generate an InvalidCastException. It is prohibitively expensive to do runtime checking on all IFooPlus operations to determine if the Detail object is in the correct state for those operations. Instead I would like the user never to be able to treat an IFoo as an IFooPlus.

我唯一想到的选择是在 Detail 内嵌入一些 IFoo 成员子类,并让 Detail 和该子类保存引用对彼此.uck.

The only option I can think of is to embed some IFoo member subclass inside of Detail and have the Detail and the subclass hold references to each other. Yuck.

是否有防止这种类型转换的最佳实践,还是应该将 IFoo 功能包含在 Detail 的成员子类中?

Is there a best practice for preventing this sort of casting, or should I just enclose the IFoo functionality in a member subclass of Detail?

推荐答案

最简单的方法是拥有一个只读包装器,该包装器引用了可写的包装器.因此, LessDetail 将始终返回相同的包装引用,但是 MoreDetail 将返回对真实"类型的引用.然后,您可以使它们都实现一个内部接口,该接口允许您执行所需的任何操作,而包装程序可能会将这些调用代理到基础对象.

The simplest approach is to have a read-only wrapper which has a reference to the writable one. So LessDetail would always return the same wrapper reference, but MoreDetail would return a reference to the "real" type. You can then make both of them implement an internal interface which allows you to do whatever you need to, with the wrapper probably proxying those calls to the underlying object.

或者,您可以尝试重新设计-就目前而言,这听起来并不理想,原因是无法在类型之间进行转换,或者是 ProcessFoo accepts 编译时的任何 IFoo ,但确实仅能处理一个特定的实现.对我来说,这感觉像是一种继承的滥用.

Alternatively, you could try to revisit your design - it doesn't sound ideal at the moment, either in terms of not being able to cast between the types or that ProcessFoo accepts any IFoo at compile-time, but is really only able to handle one particular implementation. This feels like an abuse of inheritance to me.

这篇关于防止两个接口之间的转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆