如何在C#中访问后代对象的内部方法

时间:2010-04-08 21:57:15

标签: c# inheritance internal

我正在尝试访问在父类中(在其自己的程序集中)标记为内部的方法,该方法继承自同一父代。

让我解释一下我要做的事情......

我想创建将带有基础List的IEnumberable返回给非服务类(例如UI)的Service类,并可选择将具有基础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)方法,只能看到公共GetAll()方法。

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

例如:

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

基本上我想要的是服务能够以IQueryable的形式访问其他服务方法,以便他们可以进一步优化未提交的结果,而其他人都可以获得普通的旧列表。

有什么想法吗?

修改

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

所以在我的例子中,GetAll(bool returnIQueryable)不会出现在界面中,这意味着我必须进行投射,这与我想要完成的事情背道而驰。

我不确定我是否有一个脑屁或者我是否太兴奋试图得到一些我认为干净利落的东西。无论哪种方式,感谢您的回复。

3 个答案:

答案 0 :(得分:3)

将方法公之于众的明显答案有什么问题?

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

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

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

答案 1 :(得分:0)

当您的后代类生活在同一个程序集中时,这会更容易。但是,当您的类存在于单独的程序集中时(将接口的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()); }
}

答案 2 :(得分:0)

也许我错过了一些东西,但您应该能够将其标记为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()方法。

protected internal成员对任何程序集中的所有后代类以及与基础相同的程序集中的所有类都是可见的。可访问性在这些边界之外结束。与子项相同的程序集中的非后代类将无法看到该成员。