代码之家  ›  专栏  ›  技术社区  ›  Giovanni Galbo

如何在C语言中访问子对象的内部方法#

  •  2
  • Giovanni Galbo  · 技术社区  · 14 年前

    我正试图访问一个在继承同一父类的对象的父类(在它自己的程序集中)中标记为内部的方法。

    我来解释一下我想做什么…

    我想创建将带有基础列表的IEnumerable返回到非服务类(如UI)的服务类,并且可以选择将具有基础IQueryable的IEnumerable返回到其他服务。

    我编写了一些示例代码来演示我要完成的工作,如下所示。这个例子不是真实的生活,所以评论时请记住这一点。

    所有服务都将继承类似的内容(仅显示相关代码):

    public class ServiceBase<T>
    {
        protected readonly ObjectContext _context;
        protected string _setName = String.Empty;
    
        public ServiceBase(ObjectContext context)
        {
            _context = context;
        }
    
        public IEnumerable<T> GetAll()
        {
            return GetAll(false);
        }
    
        //These are not the correct access modifiers.. I want something
        //that is accessible to children classes AND between descendant classes
        internal protected IEnumerable<T> GetAll(bool returnQueryable)
        {
            var query = _context.CreateQuery<T>(GetSetName());
            if(returnQueryable)
            {
                return query;
            }
            else
            {
                return query.ToList();
            }
        }
    
        private string GetSetName()
        {
            //Some code...
            return _setName;
        }
    
    
    
    }
    

    继承的服务如下所示:

    public class EmployeeService : ServiceBase<Employees>
    {
        public EmployeeService(ObjectContext context)
            : base(context)
        {
    
        }
    
    }
    
    public class DepartmentService : ServiceBase<Departments>
    {
        private readonly EmployeeService _employeeService;
    
        public DepartmentService(ObjectContext context, EmployeeService employeeService) : base(context)
        {
            _employeeService = employeeService;
        }
    
        public IList<Departments> DoSomethingWithEmployees(string lastName)
        {
            //won't work because method with this signature is not visible to this class
            var emps = _employeeService.GetAll(true);
    
            //more code...
        }
    }
    

    因为父类的生命是可重用的,所以它将活在与子服务不同的程序集中。当getall(bool returnqueryable)被标记为内部时,子级将无法看到彼此的getall(bool)方法,只有public getall()方法。

    我知道我可以向每个服务(或者可能是同一程序集中的中间父类)添加一个新的内部getall方法,这样程序集中的每个子服务都可以看到彼此的方法;但似乎没有必要,因为父类中已经提供了该功能。

    例如:

        internal IEnumerable<Employees> GetAll(bool returnIQueryable)
        {
            return base.GetAll(returnIQueryable);
        }
    

    本质上,我希望服务能够像iQuery那样访问其他服务方法,这样它们就可以进一步优化未提交的结果,而其他所有人都可以得到简单的旧列表。

    有什么想法吗?

    编辑

    你知道吗,我玩代码高尔夫玩得很开心…但最终我还是不能使用这个方案,因为我传递的是接口,而不是类。

    所以在我的示例中,getall(bool returniqueryable)不会出现在接口中,这意味着我必须进行强制转换,这与我试图完成的任务背道而驰。

    我不确定我是不是放了个脑筋屁,还是我太兴奋了,想得到一些我认为很好用的东西。不管怎样,谢谢你的回复。

    3 回复  |  直到 14 年前
        1
  •  3
  •   Morten Mertner    14 年前

    公开这个方法的明显答案有什么问题?

    可访问性无论如何都是不安全的,所以“邪恶的人”可以使用反射来绕过您所设置的任何修改器。由于您想从不相关的“兄弟”类调用这些方法,它们应该是公共的,因为没有“兄弟”可访问性修饰符。

    备选建议:应用 [assembly:InternalsVisibleTo("SomeOtherAssembly")] 属性授予其他业务域程序集对内部成员的访问权限。

    请注意,这会增加维护负担(如果重命名或添加程序集),使用“magic strings”,并否定内部的原始含义(因为所有内部成员现在对其他程序集也是可见的)。

        2
  •  0
  •   Daniel A.A. Pelsmaeker    14 年前

    当您的后代类将生活在同一个程序集中时,这将更容易。但是,当类位于单独的程序集中时(更改接口的 internal 关键字到 public ,但它只会阻止在不强制转换对象时调用方法。例如,铸造 InheritedClass 对象到对象 IBaseInterface 允许任何人打电话给 GetValue 方法。这是你不能真正阻止的事情,因为即使有一些关键字组合可以满足你的需要,也有人可以通过反射调用这些方法。

    internal interface IBaseInterface {
        string GetValue();
    }
    
    public abstract class MyBase : IBaseInterface {
        string IBaseInterface.GetValue()
        { return "MyBase"; }
    }
    
    public class InheritedClass : MyBase {
        public void PrintValue(IBaseInterface someclass)
        { Console.WriteLine(someclass.GetValue()); }
    }
    
        3
  •  0
  •   Anthony Pegram    14 年前

    也许我错过了什么,但你应该能把它标为 protected internal 完成你的目标。

    namespace Foo
    {
        class A
        {
            protected internal void D() { Console.WriteLine(this.ToString() + " says 'Blah'"); }
        }
    }
    
    namespace Bar
    {
        class B : Foo.A 
        {
            public B()
            {
            }
        }
    }
    
    namespace Baz
    {
        class C : Foo.A
        {
            public C()
            {
                D();
                Bar.B b = new Bar.B();
                b.D();
    
                Foo.A a = new Foo.A();
                a.D();
            }
        }
    }
    

    查看输出

    Baz.C c = new Baz.C();
    

    这都是法律规定。foo.a是基础,bar.b和baz.c继承自foo.a。void d是a.baz.c的受保护内部成员,可以按预期调用d(),还可以创建bar.b和foo.a的实例并调用它们的d()方法。

    内部受保护 成员对任何程序集中的所有子类以及与基程序集中的所有类都可见。可访问性在这些边界之外结束。与子类位于同一程序集中的非后代类将无法看到该成员。