2

私はこの問題に何度も取り組んできたので、皆さんの意見を共有して確認することにしました。次の(ばかげた)例を見てみましょう。

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() パラメータは静的でなければならないのですか?

Q2 : 私の例のように、非静的フィールドまたはメソッドを基本コンストラクターの呼び出しと組み合わせたい場合はどうなりますか? それを行うための最もOOPの方法は何ですか?

:「ベースc'torを使用しないでください」などの一時的な解決策を提供しないようにしてください。ベースの使用が避けられない、より複雑な状況が発生する可能性があるため、合理的に適切に設計されたソリューションを探しています。

ありがとう!

更新:私の例はクラックするのが簡単すぎたので、十分に学んでいないように感じるので、別の(まだかなりばかげた)例を挙げてみましょう:

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!
    }
}

この例では、ハッシュ関数が不明なハッシュ テーブルの奇妙な実装と、事前定義されたハッシュ関数を持つ int のハッシュ テーブルの特別なクラスを提供しています。ここでも、ハッシュ テーブルの非静的サイズ n を組み合わせる必要があることに注意してください。そしてベースセンター...

4

4 に答える 4

2

Q1: なぜ base() パラメーターは静的でなければならないのですか?

コンストラクターの呼び出し時にインスタンスが定義されていないため (その定義は「進行中」)、静的でなければなりません。

Q2: 私の例のように、非静的フィールドまたはメソッドを基本コンストラクターの呼び出しと組み合わせたい場合はどうなりますか? それを行うための最もOOPの方法は何ですか?

OOP のやり方は単純なメソッドのオーバーライドです。

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();
    }
}
于 2012-07-08T00:27:25.037 に答える
1

Q1Q2の両方に関して、パラメーターが静的である必要があるということではなく、パラメーターが呼び出されたときにパラメーターにアクセスできる必要があります。

また、ベースコンストラクターはローカルコンストラクターの前に呼び出されます。これが、たとえばメンバーをパラメーターとして使用できない理由thisであり、仮想呼び出しを呼び出さない理由です。

その最終的な目標が何であるかは完全にはわかりませんが、デコレータパターンに似ています。

于 2012-07-08T00:29:31.227 に答える
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()を呼び出すだけで、ハッシュコードを判別できます。ハッシュ関数を渡すために実装は必要ありません。

「インスタンスデータを操作する関数を基本クラスに送信するにはどうすればよいか」というより一般的な質問に答えるには、インスタンス変数をラムダ式でキャプチャして基本クラスに送信するか、基本クラスを使用する設計を検討する必要があります。派生クラスのインスタンス関数にアクセスする必要はありません。私は後者と一緒に行きます:)

そのような設計の1つは、関数を基本クラスの純粋な仮想呼び出しにすることです。そのためには、インスタンス化するために、派生クラスが仮想呼び出しを実装する必要があります。したがって、ここ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();
    }
}

したがって、デフォルトのハッシュコード生成関数を取得しますが、派生クラスも独自の関数を提供できます。

于 2012-07-08T00:35:08.863 に答える
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) {
    }
}
于 2012-07-08T01:15:18.643 に答える