3

次のようなジェネリック クラスのラッパー関数を作成します。

public class ColumnData
{
    public static ColumnData<T> Create<T>(string name, int width, ColumnType type,
                                          Func<T, string> dataFormater)
    {
        return new ColumnData<T>(name, width, type, dataFormater);
    }
}

メソッドはCreate、署名付きの別の関数への引数として呼び出されます。

public void populateFromData<TDATA>(IEnumerable<TDATA> data, 
                                    params ColumnData<TDATA>[] columns)   
{
   ...
}

ここでの目的は、次のことができるようにすることです。

var myData = new List<MyDataType>();
dataListView.populateFromData(
    myData,
    ColumnData.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString());

ただし、Create期待される署名に基づいてそれ自体の正しい型を推測することはできないため、ラムダもそれ自体を認識していません。

これは型推論の制限ですか、それともこのセットアップを機能させる方法はありますか?

注: 必要に応じて、この関数呼び出しのどこかに実際のデータ型を指定しても構わないと思っていますが、それぞれに指定したくありません.Create()

4

3 に答える 3

1

他の人が説明したように、あなたが望む正確な構文では不可能です。回避策として、タイピングを別の構築クラスに移動することができます。

    public class ColumnDataBuilder
    {
        public static ColumnDataBuilder<T> ColumnsFor<T>(IEnumerable<T> data)
        {
            return new ColumnDataBuilder<T>(data);
        }
    }

    public class ColumnDataBuilder<T> : ColumnDataBuilder
    {
        public IEnumerable<T> Data { get; private set; }

        public ColumnDataBuilder(IEnumerable<T> data)
        {
            this.Data = data;
        }
        public ColumnData<T> Create(string name, int width, ColumnType type, Func<T, string> dataFormater)
        {
            return new ColumnData<T>(name, width, type, dataFormater);
        }

        public void populateFromData(params ColumnData<T>[] columns)
        {
            ///...
        }
    }

    public class ColumnData<T>
    {
        public ColumnData(string name, int width, ColumnType type, Func<T, string> dataFormatter)
        {

        }
    }

次に、使用法は次のようになります。

        var builder = ColumnDataBuilder.ColumnsFor(new List<MyDataType>());
        builder.populateFromData(builder.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString()));
        IEnumerable<MyDataType> data = builder.Data;

または、あなたの例に近い使用法(あなたがあなたのを維持populateFromDataしたいdataListView場合)の場合、メソッドを捨てることができますColumnDataBuilder<T>.populateFromData(あなたのコメントからそこに保つことができないように見えるため):

        var myData = new List<MyDataType>();
        var builder = ColumnDataBuilder.ColumnsFor(myData);
        dataListView.populateFromData(myData, builder.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString()));

または、両方の長所を少し活用します。

        var builder = ColumnDataBuilder.ColumnsFor(new List<MyDataType>());
        dataListView.populateFromData(builder.Data, builder.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString()));

EDIT:あなたのコメントを考えると、あなたはおそらく に保存したくないpopulateFromDataか、おそらくIEnumerable<T> Data保存したくないColumnDataBuilderので、代わりにこれを単純化することができます:

    public class ColumnDataBuilder<T> : ColumnDataBuilder
    {
        public ColumnData<T> Create(string name, int width, ColumnType type, Func<T, string> dataFormater)
        {
            return new ColumnData<T>(name, width, type, dataFormater);
        }
    }

    public class ColumnDataBuilder
    {
        public static ColumnDataBuilder<T> ColumnsFor<T>(IEnumerable<T> data)
        {
            return new ColumnDataBuilder<T>();
        }
    }

上記の使用法では:

        var myData = new List<MyDataType>();
        var builder = ColumnDataBuilder.ColumnsFor(myData);
        dataListView.populateFromData(myData, builder.Create("ID", 40, ColumnType.Numeric, x => x.ID.ToString()));
于 2012-11-29T15:45:26.733 に答える
1

C# が実際の型であると推測できない場合、ジェネリック型パラメーターを明示的に指定する必要がある場合があります。

dataListView.populateFromData(
    myData,
    ColumnData.Create<MyDataType>("ID", 40, ColumnType.Numeric, x => x.ID.ToString());
于 2012-11-29T15:30:21.007 に答える
0

私が思いついた答えの 1 つは、エイリアスに関するものです。ラッパー クラスを削除し、CreateメソッドをColumnData<T>クラスに直接移動してから、以下を追加しました。

using ColumnData = ColumnData<MyDataType>;

ColumnData.Create()これにより、各行で型ヒントを指定する必要なく、型ヒントを使用してコンパイラにアクセスできます。これを使用する各ファイルにエイリアスを作成する必要がありますが、これは実行可能なソリューションです。

于 2012-11-29T15:54:15.297 に答える