我被这个问题解决了太多次,所以我决定分享并看看你们的想法,让我们看看以下(愚蠢)例子:
public delegate void ToRun();
class Runner {
ToRun tr;
public Runner(ToRun f) {
tr=f;
}
public void run() {
tr();
}
}
class CountingRunner : Runner {
ToRun tr;
int i;
public CountingRunner(ToRun f) : base(f+=inc) {
i=0;
}
private static void inc() {
i++; //COMPILATION ERROR - i is not (and logically cannot be) static!
}
}
好吧,我想问的是:
Q1 :为什么base()parms必须是静态的?
Q2 :如果在我的例子中,我们想要将非静态字段或方法与对基础构造函数的调用相结合,该怎么办?什么是OOP最多的方式呢?
注意:尽量不要像“只是不使用基础c'tor”这样的bandaid解决方案,因为可能会有更复杂的情况,使用base是不可避免的,所以我正在寻找一个合理的井为此设计的解决方案。
谢谢!
更新: 我的例子太容易破解,因此我觉得我还没有学到足够的东西,所以让我们尝试给另一个(相当愚蠢的)例子:
public delegate int HashFunc<E>(E e);
public interface HashTable<E> {
void insert(E e);
bool isMember(E e);
}
class HashArray<E> : HashTable<E> where E : IComparable<E> {
private E[] a;
private bool[] taken;
public readonly int n;
public int size {
get { return n; }
}
HashFunc<E> hash;
public HashArray(int m , HashFunc<E> hash ) {
n=2*m;
a=new E[n];
taken=new bool[n];
for (int i=0 ; i<n ; i++) taken[i]=false;
this.hash=hash;
}
public void insert(E e) {
int index=hash(e),i;
for (i=index ; i<n && taken[i]!=false ; ++i) ;
if (i>=n)
for (i=0 ; i<index && taken[i]!=false ; ++i) ;
if (i>=index) return;
taken[i]=true;
a[i]=e;
}
public bool isMember(E e) {
int i=hash(e);
for ( ; i<n && taken[i]!=false && a[i].CompareTo(e)!=0 ; ++i );
if (i>=n || taken[i]==false) return false;
return true;
}
}
class HashArrayInt : HashArray<int> {
public HashArrayInt(int n) : base (n,HashFunc) {
}
public static int HashFunc(int i) {
return (i%n);// n is a non static field, every hash table has its own size!
}
}
在这个例子中,我们给哈希表提供了一些奇怪的实现,其中哈希函数是未知的,并且是一个特殊的类,用于具有预定义哈希函数的整数哈希表,注意这里我们需要再次组合非静态大小哈希表n和base c'tor ......
答案 0 :(得分:1)
Q1:为什么base()parms必须是静态的?
它们必须是静态的,因为实例在构造函数调用时尚未定义(该定义是“正在进行中”)。
Q2:如果在我的例子中,我们想要将非静态字段或方法与对基础构造函数的调用相结合,该怎么办?什么是OOP最多的方式呢?
对OOP-way来说只是简单的方法覆盖。
class Runner
{
ToRun tr;
public Runner(ToRun f)
{
tr=f;
}
public virtual void Run()
{
tr();
}
}
class CountingRunner : Runner {
int i;
public CountingRunner(ToRun f) : base(f) {
i=0;
}
public override void Run() {
i++;
base.Run();
}
}
答案 1 :(得分:1)
对于 Q1 和 Q2 ,并不是参数必须是静态的,而是参数在调用时必须是可访问的。
在本地构造函数之前调用基本构造函数,这就是为什么不能使用this
成员作为参数的原因,以及为什么不应该调用虚拟调用。
不完全确定最终目标是什么,但它确实类似于Decorator pattern。
答案 2 :(得分:1)
这就是你想要的:
class Runner {
protected event Action _toRun;
public Runner() {
}
public void Run() {
var r = _toRun;
if (r != null)
_toRun();
}
}
class CountingRunner : Runner {
int i;
public CountingRunner(Action f) : base() {
_toRun += f;
}
public void inc() {
i++;
}
}
修改强>
对于您使用哈希表的特定示例,此问题可通过语言设计解决。只需在哈希表的元素上调用GetHashCode()即可确定其哈希码。您不需要实现来传递散列函数。
要回答更一般的问题“如何将函数操作实例数据发送到基类”,您应该在lambda表达式中捕获实例变量并将其发送到基类,或者考虑一个设计基类不需要访问其派生类的实例函数。我会选择后者:)
一种这样的设计是将该函数作为基类中的纯虚拟调用。这将需要派生类来实现虚拟调用以便实例化。所以在这里你将在基类中有一个abstract int GetHashCode(E item)
函数,并在你的子类中重写它。同样,在这种特定情况下,语言会为您执行此操作,并为所有类型定义虚拟GetHashCode()
函数。
这是一个非抽象示例(派生类不是必需来覆盖散列函数)。
class HashArray<E> : HashTable<E> where E : IComparable<E> {
private E[] a;
private bool[] taken;
public readonly int n;
public int size {
get { return n; }
}
public HashArray(int m) {
n=2*m;
a=new E[n];
taken=new bool[n];
for (int i=0 ; i<n ; i++) taken[i]=false;
}
public void insert(E e) {
int index= GetSpecialHashCode(e)%n;
int i;
for (i=index ; i<n && taken[i]!=false ; ++i) ;
if (i>=n)
for (i=0 ; i<index && taken[i]!=false ; ++i) ;
if (i>=index) return;
taken[i]=true;
a[i]=e;
}
public bool isMember(E e) {
int i= GetSpecialHashCode(e)%n;
for ( ; i<n && taken[i]!=false && a[i].CompareTo(e)!=0 ; ++i );
if (i>=n || taken[i]==false) return false;
return true;
}
protected virtual int GetSpecialHashCode(E item) {
return item.GetHashCode();
}
}
所以你得到一个默认的哈希码生成函数,但也欢迎派生类提供它们自己的。
答案 3 :(得分:1)
对于你的上一个例子,我认为这可行:
class HashArrayInt : HashArray<int> {
public HashArrayInt(int n) : base (n,i => HashFunc(i,n)) {
}
private static int HashFunc(int i, int n) {
return (i%n);// n is a non static field, every hash table has its own size!
}
}
如果没有,你可以这样做:
class HashFuncProvider {
private int n;
public HashFuncProvider(int n){
this.n = n;
}
public int HashFunc(int i) {
return (i%n);
}
}
class HashArrayInt : HashArray<int> {
public HashArrayInt(int n) : base (n, new HashFuncProvider(n).HashFunc) {
}
}