3

私が達成しようとしているのは、非ジェネリックとジェネリックの 2 つのクラスを持つことです。

このクラスのオブジェクトを挿入し、それらをList<T>

これがコードです

// Non-generic
public class Response
{
    public object Value { get; }
}

// Generic
public class Response<T> : Response
{
    public T Value { get; set; }
}

List<Response>このオブジェクトにアクセスすると、Value プロパティがオブジェクトとして取得されます。

しかし、このオブジェクトをジェネリックとして受け取ると、T Value プロパティにアクセスし、オブジェクトの Value プロパティを非表示にします。

そうでない場合は、明確にしてください..教えてください。

編集:これはクイズ用です。したがって、各質問には回答があります。たとえば、MultipleChoiceQuestion では、複数の回答 A、B、C、D をビュー シェイプとして持つことも、文字列や整数にすることもできます。

public abstract class Question
{
    public Question(string questionText)
    {
        this.QuestionText = questionText;
    }

    public string QuestionText { get; set; }
}

// Non-generic
public class Response
{
    public object Value { get; }
}

// Generic
public class Response<T> : Response
{
    public T Value { get; set; }
}

public class MathProblemQuestion : Question
{
    public Response Response { get; set; }
}

public class MultipleChoiseQuestion : Question
{
    public Response Response { get; set; }

    public IEnumerable<Response> PossibleResponses;

    ...
}

public class TrueOrFalse : Question
{
    ...
}
4

6 に答える 6

10

個人的には、それらに異なる名前を付けます。それはあなたの人生をよりシンプルにし、コードをより明確にします:

public abstract class Response
{
    public abstract object ObjectValue { get; }
}

public class Response<T> : Response
{
    public T Value { get; set; }

    public override object ObjectValue { get { return Value; } }
}

クラスを抽象化したことに注意してResponseください。それ以外の方法でエレガントに動作する方法を理解するのは困難です。ifResponseには then 用の独自のストレージがありValue、おそらく非値に設定できTます。このアブストラクトを作成することが問題にならないことを願っています。

于 2012-06-29T17:49:39.157 に答える
2

このクラスのオブジェクトを挿入し、それらをList<T>

よくわかりません。AList<T>は確かにジェネリック型を保持できます。

var ls = new List<List<int>>;  // works!

objectどこでも使用することにフォールバックする場合、ジェネリックを使用する意味は何ですか? 基礎となるデータ、つまり本当に重要なデータが type であるため、すべての意図と目的に対して厳密に型指定されたコレクションはなくなりましたobject

しかし、このオブジェクトをジェネリックとして受け取ると、T Value プロパティにアクセスし、オブジェクトの Value プロパティを非表示にします。

Response<object>thenを使用すると、タイプのすべてのインスタンスT が対象になります。 object

おそらく、ここで何かが欠けています。もし私がそうなら、あなたは私のために詳しく説明できますか? ジェネリック型が機能しない理由はわかりません。

編集:私は今理解していると思います。異なるジェネリック引数を持つオブジェクトを単一List<T>に保持する必要があります。Response可能であれば、特定のインターフェイスを実装するように各ジェネリック型を制限することをお勧めします。

public interface IResponseData
{
    // whatever
}

public class Response<T> where T : IResponseData
{
    public T Value { get; set; }
}

現在、共通の祖先を共有しない s やその他の型を許可する必要がある場合int、これは機能しません。Jon Skeet がより良い解決策を提供しています。

于 2012-06-29T17:49:48.943 に答える
1

必要なことを行うには、2 つの値を結び付ける必要があります。

public abstract class Response
{
    public object Value { get; set; }
}

public class Response<T> : Response
{
    private T _value;
    public new T Value
    {
        get { return _value; }
        set { base.Value = _value = value; }
    }
}

ただし、他の人が指摘したように、あなたの前提は正しくありません。ジェネリック型を他のジェネリック型の型パラメーターとして使用できます。

List<Response<YourObject>> 

完全に有効です。

于 2012-06-29T18:16:55.473 に答える
0

異なるタイプのレスポンスを同じリストに挿入し、レスポンスのオブジェクト バージョンを設定できないようにしようとしていると思います。ただし、プロパティに対して自動生成されたバッキング ストアが関連付けられていないため、以下のコードは機能しません。

// Non-generic
public class Response
{
    public object Value { get; private set; }
}
// Generic
public class Response<T> : Response
{
    public new T Value { get; set; }
}

public static void Main()
{
    List<Response> List = new List<Response>() { new Response<int>() { Value = 1 }, new Response<string>() { Value = "p" } };

    // Throws NullReferenceException
    Console.WriteLine(list[0].Value);
    Console.WriteLine(list[1].Value);
}

保護されたフィールドを使用してプロパティをバックアップする、これを試してください。

// Non-generic
public class Response
{
    protected object valueObject;

    public object Value
    {
        get
        {
            return valueObject;
        }
    }
}
// Generic
public class Response<T> : Response
{
    public new T Value
    {
        get
        {
            return (T)valueObject;
        }
        set
        {
            valueObject = value;
        }
    }
}

public static void RunSnippet()
{
    List<Response> list = new List<Response>() { new Response<int>() { Value = 1 }, new Response<string>() { Value = "p" } };

    Console.WriteLine(list[0].Value);
    Console.WriteLine(list[1].Value);
}
于 2012-06-29T18:01:06.420 に答える
0

私があなたの質問を正しく理解していれば、リスト要素を読み返すときにリスト要素を手動で型キャストする意思がある限り、あなたが望むことを行うことができます。

あなたの質問の最初の部分は、継承されたプロパティを別のタイプの新しいプロパティでどのように「隠す」のですか、そしてあなたはすでにそれを達成しています。プロパティを置き換えるのに特別なキーワードは必要ありません。あなたのサンプルタイプを考えると:

public class Response
{
    public object Value
    {
        get;
        set;
    }
}

public class Response<T> : Response
{
    public T Value
    {
        get;
        set;
    }

}

次のことはすでに実行できます。

// typeof(response.Value) == System.Object
var response = new Response();

// typeof(responseint.Value) == System.Int32
var responseint = new Response<int>();

ただし、さらに求めていること、それらを に入れてList<Response>も派生型として扱うことは、明示的な型キャストなしでは機能しません。a の要素の型はList<>コンパイル時に固定され、コンパイラが認識する限り、リストのすべての要素がその型を持ちます。必要に応じて、さらに派生型をリストに追加できますが、それらがそこにあると、戻ったときに、コンパイラーはそれらが基本型であることしか認識しません。

もちろん、実行時には実際の型メタデータが存在するため、それが実際のものである限りResponse、ランタイムは a を aに変換する方法を知っています。上記のとのインスタンスを指定して、コードで説明するには:Response<int> ResponseResponse<int>

 // this part is fine, but...
var responses = new List<Response>();
responses.Add(response);
responses.Add(responseint); 

// This will not work.
responses[1].Value += 1; 

// But this will.
(responses[1] as Response<int>).Value += 1;
于 2012-06-29T18:01:30.143 に答える
0

以下を実行すると (「new」キーワードを使用)、基本クラスのプロパティが非表示になります。

// Non-generic
public class Foo
{
    public object Value { get; set; }
}

// Generic
public class Foo<T> : Foo
{
    public new T Value { get; set; }
}

別の名前の別のプロパティを追加しない限り、それを回避する方法はわかりません。List< Foo < T > > を持つことができるリストを使用するために、クラスの異なるバージョンが必要な理由を完全には理解していません。

于 2012-06-29T17:51:51.430 に答える