48

これが奇妙なことなのか、それともコードの臭いなのかはわかりませんが、「キャスト」する方法(ある種のoopパターンがいいでしょう)があるのではないかと思っていました。基本型から派生型の形式へ。派生型には、親が提供しない追加の機能があり、それ自体は基本的に健全ではないため、これはほとんど意味がないことを私は知っています。しかし、これを行う方法はありますか?これが私が求めていることをよりよく説明できるようにするためのコード例です。

public class SomeBaseClass {
    public string GetBaseClassName {get;set;}
    public bool BooleanEvaluator {get;set;}
}

public class SomeDerivedClass : SomeBaseClass {
    public void Insert(SqlConnection connection) {
          //...random connection stuff
          cmd.Parameters["IsItTrue"].Value = this.BooleanEvalutar;
          //...
    }
}

public static void Main(object[] args) {
    SomeBaseClass baseClass = new SomeBaseClass();
    SomeDerivedClass derClass = (SomeDerivedClass)baseClass; 
    derClass.Insert(new sqlConnection());
}

私はこれが間抜けに見えることを知っていますが、この種の何かを達成する方法はありますか?

4

17 に答える 17

31

「管理された」言語では、健全ではありません。これはダウンキャストであり、あなたが説明した理由から、それを処理するための正しい方法はありません(サブクラスは基本クラス以上のものを提供します-これはどこから来るのですか?)。特定の階層に対して同様の動作が本当に必要な場合は、基本型をプロトタイプとして使用する派生型のコンストラクターを使用できます。

単純なケース(加算状態のないより具体的なタイプ)を処理するリフレクションを使用して何かを構築することができます。一般に、問題を回避するために再設計するだけです。

編集:うわー、基本/派生型間の変換演算子を書くことはできません。あなた自身から「あなたを守ろう」としているマイクロソフトの奇妙なこと。ええと、少なくとも彼らは太陽ほど悪くはありません。

于 2008-09-23T22:37:16.460 に答える
19

継承の代わりに合成を試してください!

SomeBaseClass のインスタンスを SomeDerivedClass に渡すほうがよいように思えます (これは基本クラスを派生させなくなり、そのように名前を変更する必要があります)

public class BooleanHolder{       
    public bool BooleanEvaluator {get;set;}
}

public class DatabaseInserter{
    BooleanHolder holder;

    public DatabaseInserter(BooleanHolder holder){
        this.holder = holder;
    }

    public void Insert(SqlConnection connection) {
          ...random connection stuff
          cmd.Parameters["IsItTrue"].Value = holder.BooleanEvalutar;
          ...
    }
}

public static void Main(object[] args) {
    BooleanHolder h = new BooleanHolder();
    DatabaseInserter derClass = new DatabaseInserter(h);
    derClass.Insert(new sqlConnection);
}

http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html (3 ページ)を参照してください。

コンポジションによるコードの再利用 コンポジションは、Apple が Fruit の Peel() の実装を再利用する別の方法を提供します。Fruit を拡張する代わりに、Apple は Fruit インスタンスへの参照を保持し、Fruit で Peel() を呼び出すだけの独自の Peel() メソッドを定義できます。

于 2008-09-24T00:15:02.077 に答える
16

個人的には、この場合に継承を使用するのは面倒だとは思いません。代わりに、コンストラクターで基本クラスのインスタンスを渡し、メンバー変数を介してアクセスします。

private class ExtendedClass //: BaseClass - like to inherit but can't
{
    public readonly BaseClass bc = null;
    public ExtendedClass(BaseClass b)
    {
        this.bc = b;
    }

    public int ExtendedProperty
    {
        get
        {
        }
    }
}
于 2012-09-26T09:25:41.900 に答える
9

派生クラスのオブジェクトがあり、それが基本クラス型の参照によって参照されていて、何らかの理由で派生クラス型参照によって参照されるようにしたい場合、ダウンキャストは理にかなっています。つまり、ダウンキャストして、前のアップキャストの効果を逆にすることができます。ただし、派生クラス型の参照によって参照される基本クラスのオブジェクトを持つことはできません。

于 2008-09-23T22:46:43.850 に答える
7

私はこれをお勧めすると言っているのではありません。ただし、基本クラスをJSON文字列に変換してから、派生クラスに変換することはできます。

SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));
于 2012-05-01T21:02:07.373 に答える
5

C# 言語ではそのような演算子を使用できませんが、これらを記述して機能させることはできます。

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) { ... }

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) { ... }
于 2013-04-13T12:17:02.507 に答える
5

いいえ、これは不可能です。C# のようなマネージ言語では機能しません。コンパイラが許可しても、ランタイムはそれを許可しません。

あなたはこれがばかげているようだと自分自身に言いました:

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 

自問してみてください、class実際には のインスタンスSomeDerivedClassですか? いいえ、変換は意味がありません。SomeBaseClassに変換する必要がある場合はSomeDerivedClass、コンストラクターまたは変換メソッドのいずれかの種類の変換を提供する必要があります。

ただし、クラス階層に何らかの作業が必要なようです。一般に、基本クラスのインスタンスを派生クラスのインスタンスに変換することはできません。通常、基本クラスには適用されないデータや機能が存在するはずです。派生クラスの機能が基本クラスのすべてのインスタンスに適用される場合は、基本クラスにロールアップするか、基本クラス階層の一部ではない新しいクラスにプルする必要があります。

于 2008-09-23T22:53:59.387 に答える
1

はい - これはコードの匂いであり、継承チェーンが壊れているという事実をほぼ突き止めています。

(限られたサンプルから)私の推測では、DerivedClass を SomeBaseClass のインスタンスで操作することをお勧めします。そのため、「DerivedClassSomeBaseClass です」ではなく、「DerivedClassにはSomeBaseClass があります」。これは、「継承より合成を優先する」として知られています。

于 2008-09-23T23:14:02.957 に答える
1

現在、基本クラスと派生クラスの両方が実装するインターフェイスについて考えたことはありますか? このように実装している理由の詳細はわかりませんが、うまくいくかもしれません。

于 2009-10-19T14:54:44.650 に答える
0

なぜ誰もこれを言っていないのかわかりません。何かを見逃している可能性がありますが、asキーワードを使用でき、ifステートメントを実行する必要がある場合はifを使用します。

SomeDerivedClass derClass = class as SomeDerivedClass; //derClass is null if it isnt SomeDerivedClass
if(class is SomeDerivedClass)
    ;

-編集-私はずっと前にこの質問をしました

于 2010-01-14T20:27:25.863 に答える
0

それはうまくいきません。コンパイルエラーによってリンクされているヘルプページを見てください。

最善の解決策は、ここでファクトリメソッドを使用することです。

于 2008-09-23T22:37:51.187 に答える
0

私は最近、いくつかのプロパティを追加するために、派生型を使用して単純なDTOを拡張する必要がありました。次に、内部データベースタイプからDTOまで、持っていた変換ロジックを再利用したいと思いました。

私がそれを解決した方法は、次のように使用して、DTOクラスに空のコンストラクターを適用することでした。

class InternalDbType {
    public string Name { get; set; }
    public DateTime Date { get; set; }
    // Many more properties here...
}

class SimpleDTO {
    public string Name { get; set; }
    // Many more properties here...
}

class ComplexDTO : SimpleDTO {
    public string Date { get; set; }
}

static class InternalDbTypeExtensions {
    public static TDto ToDto<TDto>(this InternalDbType obj) where TDto : SimpleDTO, new() {
        var dto = new TDto {
            Name = obj.Name
        }
    }
}

その後、複雑なDTOに変換するときに、単純なDTOからの変換ロジックを再利用できます。もちろん、他の方法で複合型のプロパティを入力する必要がありますが、単純なDTOの多くのプロパティを使用すると、IMOが非常に単純化されます。

于 2012-03-13T15:27:16.323 に答える
0

これはダウンキャストと呼ばれ、「安全な」バージョンを使用するという Seldaek の提案は適切です。

これは、コードサンプルを使用したかなり適切な説明です。

于 2008-09-23T22:39:30.810 に答える
0

派生クラスが持つ「追加」をどのように取得するので、これは不可能です。インスタンス化したときに、derivedClass2 ではなく、derivedClass1 を意味していることをコンパイラはどのように認識しますか?

あなたが本当に探しているのはファクトリ パターンまたはそれに類似したものだと思うので、インスタンス化されている明示的な型を実際に知らなくてもオブジェクトをインスタンス化できます。あなたの例では、「Insert」メソッドを持つことは、ファクトリが返すインスタンスが実装するインターフェイスになります。

于 2008-09-23T23:01:32.830 に答える
-1

C ++は、コンストラクターを使用してそれを処理します。C++型キャスト。それは私には見落としのようです。あなたの多くは、プロセスが追加のプロパティで何をするかという問題を提起しました。私は答えます、プログラマーがプロパティを設定しないときに派生クラスを作成するとき、コンパイラは何をしますか?私はこの状況をC++と同様に処理しました。基本クラスを取得するコンストラクターを作成してから、コンストラクターのプロパティを手動で設定します。これは、派生クラスに変数を設定して継承を解除するよりも確実に望ましい方法です。結果のコードは見た目がすっきりすると思うので、ファクトリメソッドよりもそれを選択します。

于 2012-01-24T16:22:45.737 に答える