3

怎么可能知道一个对象是否实现了索引器?,我需要为 DataRow 和 IDataReader 共享一个逻辑,但它们不共享任何接口。

我也尝试过使用泛型,但不知道应该对 where 子句施加什么限制。

public class Indexer {
    // myObject should be a DataRow or a IDataReader
    private object myObject;
    public object MyObject {
        get { return myObject; }
        set { myObject = value; }
    }
    // won't compile, myObject has no indexer
    public object this[int index] {
        get { return myObject[index]; }
        set { myObject[index] = value; }
    }
    public Indexer(object myObject) {
        this.myObject = myObject;
    }
}

public class Caller {
    void Call() {
        DataRow row = null;
        IDataReader reader = null;
        var ind1 = new Indexer(row);
        var ind2 = new Indexer(reader);
        var val1 = ind1[0];
        var val2 = ind1[0];
    }
}
4

3 回答 3

5

您需要声明一个带有索引器属性的接口,将该接口用作约束,并且类型参数类需要实现该接口以满足约束。

由于您无法控制要使用的类,因此这是行不通的。

另一种方法是让Indexer类将 get/set 操作作为单独的参数:

public class Indexer {

    private Func<int, object> getter;        
    private Action<int, object> setter;

    public object this[int index] 
    {
        get { return getter(index); }
        set { setter(index, value); }
    }

    public Indexer(Func<int, object> g, Action<int, object> s) 
    {
        getter = g;
        setter = s;
    }
}

public static class IndexerExtensions
{
    public static Indexer ToIndexer(this DataRow row)
    {
        return new Indexer(n => row[n], (n, v) => row[n] = v);
    }

    public static Indexer ToIndexer(this IDataReader row)
    {
        return new Indexer(n => row[n], (n, v) => row[n] = v);
    }
}

然后你可以这样做:

DataRow row = null;
IDataReader reader = null;
var ind1 = row.ToIndexer();
var ind2 = reader.ToIndexer();
var val1 = ind1[0];
var val2 = ind1[0];
于 2009-03-26T22:34:59.580 回答
3

您可以使您的索引器成为一个抽象基类,具有两个子类,一个用于 DataRow,一个用于 IDataReader。

为了使其更易于使用,可以存在 2 种工厂方法,例如:

var ind1 = Indexer.CreateFromDataRow(row);
var ind2 = Indexer.CreateFromIDataReader(reader);

他们可以为该类型创建一个特定的基类,并使用它自己的逻辑来处理索引。

这避免了为每个 get/set 调用不断检查类型的开销(以单个虚拟属性而不是标准属性为代价)。

于 2009-03-26T22:40:22.420 回答
1
get { 
    DataRow row = myObject as DataRow;
    if (row != null)
        return row[index];
    IDataReader reader = myObject as IDataReader;
    if (reader != null)
        return reader[index];
}

并对 set{} 使用相同的逻辑

于 2009-03-26T22:38:52.987 回答