受保护的静态方法可见性

本文关键字:可见性 静态方法 受保护 | 更新日期: 2023-09-27 18:01:02

考虑一下这种情况:(注意,为了简洁起见,省略了类型和方法体(

这让我在需要的时候连接到数据。

public abstract class DatabaseAccessor {
    protected static object GetDataFromDatabase(...) {...} 
    protected static object UpdateSomething(...) {...}
}

这管理缓存——如果我向ServerCache请求资源,但它没有,那么ServerCache可以使用DatabaseAccessor来获得它所需要的。我不直接提供对缓存资源的访问。

public abstract class ServerCache : DatabaseAccessor {
    private static object CachedResources;
    protected static object GetFromCacheOrGetFresh(...) {...}
    protected static void InvalidateCache(...) {...}
}

这是一种提供访问缓存数据或新数据、发送更新、使缓存资源无效/过期的方法的服务。

public class DepartmentsService : ServerCache {
    public static object Read() {
        ...
        return ServerCache.GetFromCacheOrGetFresh();
    }
    public static object Update(string id) {
        ...
        DatabaseAccessor.UpdateSomething(...);
        ServerCache.InvalidateCache(...);
        return DepartmentsService.Read().Where(record => record.Id == id);
    }
    public static object Create(...){...}
}

这一直很有效,直到我需要创建额外的服务,就像上面的一样。事情是这样的:

public class EmployeeService : ServerCache {
    ...
    public static object Create(object creation) {
        //check first service to see if creation is valid 
        //by checking that the DepartmentsService contains creation.Department.
        DepartmentsService.Read().Where(..... problem            
    }
}

在非派生类中调用DepartmentsService OUTSIDE of DepartmentsServices时,我能够看到ServerCache的所有受保护方法。

在设计中,WebApi控制器同时使用DepartmentsService和EmployeeService。控制器不是从ServerCache继承的,并且方法按预期隐藏。

仅仅因为DepartmentsService和EmployeesService都是从ServerCache派生的,这并不意味着EmployesService应该能够调用DepartmentsSService本质上私有的方法。

关于受保护的修饰符,我缺少什么
当protected与static一起使用时,我是否遗漏了一些细微之处
这是"方法隐藏"发生的时候吗

受保护的静态方法可见性

DepartmentsServiceEmployeeService bot继承自ServerCache,而其自身继承自DatabaseAccessor

EmployeeService能看到什么

首先,它可以看到所有其他类的所有公共成员,包括DepartmentsService。此外,它可以看到DatabaseAccessorServerCache的所有受保护方法,因为它在继承层次中低于它们。

这是它可以看到的列表:

protected static DatabaseAccessor.GetDataFromDatabase(...)
protected static DatabaseAccessor.UpdateSomething(...)
protected static ServerCache.GetFromCacheOrGetFresh(...)
protected static ServerCache.InvalidateCache(...)
public static DepartmentsService.Read()
public static DepartmentsService.Update(string id)
public static DepartmentsService.Create(...)

protected成员被继承后会发生什么

它保持原样:基类的protected成员。它在基类上下文中执行,除非它被new-关键字(或virtualoverride,在您的情况下是不允许的,因为它都声明为static(覆盖。因此,它对父类的所有子类都可见。

这是一个需要注意的要点,也是liskov替换原则的驱动因素之一,该原则基本上说,应该能够将子类的实例分配给其基类的引用,然后调用基类成员,它的行为应该像期望基类实例的行为一样,而不知道这在现实中是子类实例。

让我用给定的例子向您展示这意味着什么,假设方法而不是static:

DatabaseAcccessor accessor = new ServerCache();
var data = accessor.GetDataFromDatabase(...); 

行为应与完全相同

ServerCache accessor = new ServerCache();
var data = accessor.GetDataFromDatabase(...); 

因为您永远无法知道变量或参数是否引用了派生类型实例。

因此,在使用newoverride时要始终小心,并且通常倾向于组合而非继承。

处理您的评论

如何防止DatabaseAccessor的受保护方法从EmployeeService调用到DepartmentService

这需要一点重组。我建议将ServerCache设置为Singleton或Monostate。让我们去辛格尔顿:

public class ServerCache : DatabaseAccessor {
    private object CachedResources;
    private static readonly ServerCache instance;
    private ServerCache(){ /* private ctor to prevent instances from beeing createt anywhere but in this class */ }
    private static ServerCache Instance 
    {
        get
        {
            if(instance==null)
               instance = new ServerCache();
            return instance;
        }
    }
    public object GetFromCacheOrGetFresh(...) {...}
    public void InvalidateCache(...) {...}
}

现在可以在DepartmentsServiceEmployeeService中创建ServerCache变量,而不是从ServerCache继承。这样一来,ServerCache方法将不可用,例如DepartmentsService的protected方法。