关于索引器和/或泛型的问题

发布于 2024-07-16 18:00:12 字数 839 浏览 10 评论 0原文

如何知道一个对象是否实现了索引器?,我需要共享 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];
    }
}

how is it possible to know whether an object implements an indexer?, I need to share a logic for a DataRow and a IDataReader, but they don't share any interface.

I tried also with generics but don't know what restriction should I put on the where clause.

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];
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

葵雨 2024-07-23 18:00:12

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

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

另一种方法是让 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];

You'd need to declare an interface with an indexer property, use that interface as the constraint, and the type argument class would need to implement that interface in order to satisfy the constraint.

As you don't control the classes you want to use, that wouldn't work.

An alternative is to make the Indexer class take the get/set operations as separate parameters:

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);
    }
}

You could then do this:

DataRow row = null;
IDataReader reader = null;
var ind1 = row.ToIndexer();
var ind2 = reader.ToIndexer();
var val1 = ind1[0];
var val2 = ind1[0];
薄情伤 2024-07-23 18:00:12

您可以将 Indexer 设为一个抽象基类,其中包含两个子类,一个用于 DataRow,一个用于 IDataReader。

为了更容易使用,可以存在 2 个工厂方法,例如:
<代码>

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

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

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

You could make your Indexer an abstract base class, with two subclasses, one for DataRow, and one for IDataReader.

To make it easier to use, 2 factory methods could exist, such as:

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

They could create a specific base class for that type, with it's own logic for handling the indexing.

This avoids the overhead of checking types constantly for every get/set call (at the cost of a single virtual property instead of a standard property).

简单爱 2024-07-23 18:00:12
get { 
    DataRow row = myObject as DataRow;
    if (row != null)
        return row[index];
    IDataReader reader = myObject as IDataReader;
    if (reader != null)
        return reader[index];
}

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

get { 
    DataRow row = myObject as DataRow;
    if (row != null)
        return row[index];
    IDataReader reader = myObject as IDataReader;
    if (reader != null)
        return reader[index];
}

and use the same logic for set{}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文