web-dev-qa-db-ja.com

ジェネリックオブジェクトのジェネリックリスト

データのフィールドを表すオブジェクトがあるとします。そのオブジェクトには、名前、タイプ、値、長さのプロパティが必要です。ここにオブジェクトがあります:

class Field<T>
{
    public string Name { get; set; }
    public Type Type
    {
        get
        {
            return typeof(T);
        }
    }
    public int Length { get; set; }
    public T Value { get; set; }
}  

コードのユーザーに特定のタイプの値のみを割り当てられるようにしたいので、私はジェネリックを使用しました。
今問題は、フィールドのリストを作成したいときです。
List<Field<object>>のようなリストを作成すると、リストの特定のフィールドに任意の値を割り当てることができ、Typeを照会すると、「オブジェクト」が取得されます。
問題は-そのリストでは、文字列を保持するいくつかのフィールド、整数、日付を保持するいくつかのフィールド、さらにはフィールドのリストを持つカスタムオブジェクトが必要な場合があります...
Genericsはそのようなものに対する良い解決策ですか?はいの場合、どのように実装しますか?そうでない場合、より良い方法は何ですか?

---編集---
背景を追加するだけです:
1。フィールドのリストが必要な場合があり、各フィールドには次のように異なるデータ型が保持されます。

List<Field<object>> lst = new List<Field<object>>();
lst.Add(new Field<string>());
lst.Add(new Field<int>());
lst.Add(new Field<SomeObjectFromMyApp>());

2.後で、これらのオブジェクトとその属性をループで自動的に照会する必要があります。

foreach(Field<object> fld in lst)
{
    Type t = fld.Type;
    //do some other stuff
}
21

はい、ジェネリック医薬品は良い選択です。タイプセーフを実現する(およびTypeプロパティでタイプを識別する)キーは、リストとField<T>クラスの間に抽象化を追加することです。

Field<T>にインターフェースIFieldを実装してもらいます。このインターフェイスにはメンバーは必要ありません。

次に、リストをList<IField>として宣言します。

これにより、リストにフィールドのみが含まれるように制約できますが、各フィールドは異なるタイプにすることができます。

後で値を読み取るには、次のようにします

foreach(var field in list)
{
    var type = field.Type;
    ....
}
18
David Arno

インターフェイスを定義して、Field<T>がそのインターフェイスを実装することをお勧めします

public interface IField
{

}

public class Field<T> : IField
{
    public string Name { get; set; }
    public Type Type
    {
        get
        {
            return typeof(T);
        }
    }
    public int Length { get; set; }
    public T Value { get; set; }
}

あなたはこのコードを書くことができます:

var list = new List<IField>();

このリストには、タイプField<T>のオブジェクトを含めることができます

13
VahiD

数人のコメント者がすでに述べたように、空のインターフェースを作成するとTypeプロパティにアクセスできないので、代わりに次のようにします。

public interface IField
{
    Type Type { get; }

    string Name { get; set; }

    int Length { get; set; }
}

public class Field<T> : IField
{
    public string Name { get; set; }

    Type IField.Type => typeof(T);

    public int Length { get; set; }

    public T Value { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}

次に、valueプロパティがどのデータ型であるかを確認し、オブジェクトを正しい型にキャストできます。

class Program
{
    static void Main(string[] args)
    {
        var fieldList = new List<IField>()
        {
            new Field<string>()
            {
                Value = "Hello World!", 
                Length = 12, 
                Name = "A string"
            },
            new Field<int>()
            {
                Value = 4711,
                Length = sizeof(int),
                Name = "An integer value"
            },
            new Field<double>()
            {
                Value = 2.4,
                Length = sizeof(double),
                Name = "A double value"
            },
        };

        foreach (var field in fieldList)
        {
            if (field.Type == typeof(string))
            {
                PrintField(field, "String value:");
            }
            else if (field.Type == typeof(int))
            {
                PrintField(field, "Integer value:");
            }
            else if (field.Type == typeof(double))
            {
                PrintField(field, "Double value:");
            }
        }
    }

    static void PrintField(IField field, string info)
    {
        Debug.WriteLine(info);
        Debug.WriteLine($"\tName: {field.Name}, Length: {field.Length}, Value: {field}");
    }
}

コードは次の出力を生成します。

// String value:
//  Name: A string, Length: 12, Value: Hello World!
// Integer value:
//     Name: An integer value, Length: 4, Value: 4711
// Double value:
//     Name: A double value, Length: 8, Value: 2,4
2
Michael Trapp