C#:派生クラスで異なる戻り値の型を持つプロパティ

私はこの問題の答えを探し出そうとしましたが、それを正しく探す方法がわからないので、ほとんど見つけられませんでした。すべての助けは非常に感謝しています。

ベースクラスは次のようになります

abstract public class Property
{
    private String name;

    public Property(String propertyName)
    { 
        name = propertyName; 
    }

    public String Name
    {
        get { return name; }
    }

    abstract public override String ToString();
}

そして、似たような派生クラス

public class StringProperty : Property
{
    private String value;//different properties for different types

    public StringProperty(String propertyName, String value) : base(propertyName)
    {
        this.value = value;
    }

    public String Value//different signature for different properties
    {
        get { return value; }
    }

    public override String ToString()
    {
        return base.Name + ": " + value;
    }
}

実行時に、関数は "Property"オブジェクトの集合を受け取ります。それぞれの "価値"を得るためには、私は何をする必要がありますか?各 "Property"オブジェクトのタイプを照会するために大きな if ステートメントが必要ですか?そうでない場合、より洗練されたソリューションがありますか?

抽象的な "Value"プロパティをオーバーライドするように定義しようとしましたが、戻り値の型が異なるため動作しませんでした。私は "Value"プロパティをシャドーイングして試してみましたが、動作させることができませんでした。 COMのようなVariantを使用するという考えは、あまり適切ではないと思います。

ありがとうございます。

編集:

私は何をしようとしているのかについての詳細を加えておくべきだった。プロパティは、Winformsアプリケーションに表示されます。異なる "TextBox"は異なるプロパティを表し、適切な入力のためにフィルタリングされます(タイプによって異なります)。更新された値は読み出されて保存されます。コンテナオブジェクトはJSONにシリアル化され、AndroidおよびiPhoneクライアントでデシリアライズされ、最終的にはこれらの値がOpenGLの処理を行うネイティブC ++コードを実行するレイヤーに渡されます。私はすべての必要なプロパティの種類を事前に知っていないので、仲介人として、OpenGLエンジンにフィードできるようにしながらコードをできるだけ堅牢にしたいと考えました。

7
あなたはその価値をどうしたいのですか?
追加された 著者 Lasse Vågsæther Karl,
しかし、これはもちろんの変形です。 ダイナミックにすることで、C#のようなハッピーな顔を描くことができます。
追加された 著者 Hans Passant,
質問テキストに詳細を追加しました。
追加された 著者 alokoko,

4 答え

ジェネリッククラスを使用することができます:

public class AnyProperty : Property
{
    private T value;
   //... etc

私は本当にベースクラスを今インターフェイスで作ることをお勧めします:

public interface IProperty
{
    public String Name { get; }
}

public class Property : IProperty
{
    public Property(String name, T value)
    {
        Name = name;
        Value = value;
    }

    public String Name { get; private set; }
    public T Value { get; private set; }

    public override String ToString()
    {
        return string.Format("{0}: {1}", Name, Value)
    }
}

使用例は次のとおりです。

var intProp = new Property       ("age", 32);    
var strProp = new Property    ("name", "Earl");    
var enumProp = new Property ("eye color", ColorEnum.Magenta);    

構築をさらに簡単にするには、ファクトリメソッドを使用できます。

public static Property MakeProperty(string name, T value)
{
    return new Property(name,value);
}

var intProp = MakeProperty("age", 32);    
var strProp = MakeProperty("name", "Earl");    
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);    

Not necessarily recommended, and a bit OT:

あなたは拡張メソッドでそれをもっと楽しくすることもできます:

public static Property AsProp(this T value, string name)
{
    return new Property(name,value);
}

var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");
13
追加された
@オーティーエル:いいえ、特に理由はありません。 (正直なところ、それを定義/使用する場所によって異なります)。静的にすることもできますので、私はそれを反映するようにコードを編集します。
追加された 著者 sehe,
MakeProperty メソッドを静的にする必要はありませんか?
追加された 著者 Otiel,
+1。優雅な答えを提供する時間をとってくれてありがとう、ありがとう。私の場合は、UIのやりとりとプロパティの構造についての詳細なものでした。そして、ミニテクの答えは私に行く方向を与えました。次のステップとして、私はあなたの答えをより詳細に検査し、私たちのケースに合うようにアイデアを組み入れます。
追加された 著者 alokoko,

単純に object 型を使用する必要があります。あなたは何を達成しようとしていますか?ここでの問題は、クラスの構造ではなく、 Property オブジェクトのコレクションを受け取る関数です。未知の型にキャストすることは不可能です。なぜなら、格納する必要がある変数の型がわからないからです。

したがって、基本的に Property.Value プロパティは object タイプである必要があります。 Property オブジェクトを使用するメソッドでは、何かを行う必要があります。どのようにして構造化するかを決定します。値を印刷していますか? PropertyValue クラスから継承する * Value クラスを持ち、適切な文字列表現を返すように ToString()をオーバーライドします。

3
追加された
@alokoko:その場合、クラスは自分のディスプレイを処理する必要があります。メソッド Control FetchControl()とメソッド void ApplyChanges(Control c)(たとえば、命名の柔軟性)を持ち、クラスに独自のコントロールを作成させます。次に、フォームにコントロール(おそらく TextBox )を配置し、編集が完了したら ApplyChanges をコントロールに戻して、適用された変更を適用できます。
追加された 著者 Ry-,
:-)私は詳細を追加する必要があります。質問に私の編集を参照してください...
追加された 著者 alokoko,
はい、そのアプローチはうまくいきました。すぐにこのことを私に教えてくれてありがとう!
追加された 著者 alokoko,
マイクロソフトはこの非常に技術をSSISで使用しています。変数クラス。
追加された 著者 Edmund Schweppe,

少し考え直す必要がありますが、ダイナミックタイプ(.net4で導入されています)

あなたの問題を本当に解決するわけではありませんが、それを横取りします。 あなたのプロパティは基本的には

Dictionary

、彼らは実行時まで評価されないので、タイピングのためのコンパイラサポートは得られません。

あなたが望むように与えられた int SomeValue = MyProperties [SomePropertyName] + 10;

だから MyProperties [SomePropertyName] = 10;//すべてが良いです

その76.52またはFredの場合、追加は実行されるポイントで例外をスローします。

コードははるかに簡単でクリーナーで、余分なキャストは必要なく、必要な足場の量は最小限ですが、辞書を広範囲かつ宗教的に使用するユニットテストコードが必要です。

2
追加された
うわー、 dynamic について聞いたことはありませんでした。 VB.NET 4.0には存在しないと思います。 :( +1
追加された 著者 Ry-,
明らかにファッジのビット[リンク] stackoverflow.com/questions/2889974/…
追加された 著者 Tony Hopkinson,
「動的」キーワードについてお知らせいただきありがとうございます。
追加された 著者 alokoko,

私はあなたのサンプルコードにいくつかの変更を加え、この結果を得ました...

   abstract public class Property
    {
        private readonly String _name;
        public Property(String propertyName)
        {
            _name = propertyName;
        }
        public String Name
        {
            get { return _name; }
        }
        abstract public override String ToString();
    }
    public class StringProperty : Property
    {
        private readonly dynamic _value;//different properties for different types 
        public StringProperty(String propertyName, dynamic value)
            : base(propertyName)
        {
            this._value = value;
        }
        public dynamic Value//different signature for different properties 
        {
            get { return _value; }
        }
        public override String ToString()
        {
            return base.Name + ": " + _value;
        }
    }
    static void Main(string[] args)
    {
        StringProperty sp = new StringProperty("A double", 3.444);
        StringProperty sp2 = new StringProperty("My int", 4343);
        StringProperty sp3 = new StringProperty("My directory", new  DirectoryInfo("Some directory"));
        StringProperty sp4 = new StringProperty("My null", null);
        Console.WriteLine(sp);
        Console.WriteLine(sp2);
        Console.WriteLine(sp3);
        Console.WriteLine(sp4);
    }
}

値は、期待どおりにコンソールに正しく出力されます。

2
追加された
この場合、なぜ「ダイナミック」は「オブジェクト」より優れていますか?
追加された 著者 zmbq,
zmbqへ。そうではないかもしれないが、私はこの事件について十分に知りません。しかし、オブジェクトを使用しているある時点では、明示的なキャストを使用するため、結果はたとえばiffy(int) "10"となる可能性があります。つまり、あなたの財産がどんなタイプであるべきかを知らないことに対処するために、ますます足場を打ち上げることになり、新しいタイプごとに足場を追加する必要があります。ダイナミックはそれを解決しますが、あなたには他の問題を与えます。それは設計上の選択肢であり、それを見て、最も妥協しにくい場所を見なければなりません。
追加された 著者 Tony Hopkinson,