使用索引器的存在作为方法的参数签名/合约/类型

本文关键字:参数 类型 方法 合约 索引 存在 | 更新日期: 2023-09-27 18:14:04

作为示例,我将使用SqlDataReader和DataRow类:它们都定义了以下索引器:

public object this[int columnIndex] { get; set; }

作为方法的参数类型使用的最小公分母类型是什么,以便两者(以及实现相同索引器的任何其他类)可以以相同的方式传递和使用,例如:

void DoSomething(??? indexedObject)
{
   string foo = indexedObject[0].ToString(); 
          // let's ignore the presence of ToString()
          // for the purpose of this question
}

object吗?如果索引对象不是来自object(我认为这是可能的,即使非常不可能)。

如果重要的话,我的目标是。net 3.5。

编辑:我正在寻找一些合同强制执行,导致调用者传递实现所述索引器的对象。

使用索引器的存在作为方法的参数签名/合约/类型

是object吗?

差不多。没有可以使用的公共接口或类,所以object实际上是唯一保证在层次结构中共享的东西。

如果被索引的对象不是从object派生的怎么办?

这在。net中是不可能的。System.Object是所有类型的基本类型,并且值总是可以被视为对象(即使它们需要装箱才能工作)。

但是,作为object传入将不提供对索引器的访问,除非通过反射。

唯一直接的方法是通过dynamic,但这需要。net 4(并且不是类型安全的,这意味着你可能会得到运行时异常)。

一个更好的方法可能是提供一个Func<T, int, string>,它允许您在调用现场指定如何提取值:

void DoSomething<T>(T object, Func<T, int, string> valueExtractor)
{
    string foo = valueExtractor(object, 0); 
}

然后调用:

DoSomething(indexedObject, (o,i) => o[i].ToString());

这允许您传入一个对象和一种机制,以在调用站点给定索引提取值,这适用于任何类型。


编辑关于:

编辑:我正在寻找一些合同强制执行,导致调用者传递实现所述索引器的对象。

没有一个内置的契约或接口来实现这些类型,也没有任何方法来约束基于索引器存在的泛型。您将需要一种不同的方法,例如我建议使用委托来提取值。

我想说Reed Copsey的Func<T>委托解决方案是最好的方法,但是由于你使用的是c# 3.5,你将不得不去定义你自己的委托,Func<T>将不可用。

编辑——哦,这是3.5而不是4.0。

无论如何,这里有另一个解决方案,正如我在评论中概述的那样,使用接口来定义适配器类型,以理解如何调用专用类型索引器,但允许调用站点(DoSomething)使用公共接口:

void Main()
{
    var t1 = new Type1(); // ie Sql Reader
    var t2 = new Type2(); // ie DataRow
    DoSomething(new Type1IndexAdapter(t1));
    DoSomething(new Type2IndexAdapter(t2));
}
public void DoSomething(ICanIndex indexer)
{
    var r = indexer["test"];
}
public interface ICanIndex
{
    string this[string index]{get;}
}
public class Type1IndexAdapter : ICanIndex
{
    public Type1 value;
    public Type1IndexAdapter(Type1 val)
    {
        this.value = val;
    }
    public string this[string index]
    {
        get
        {
            return this.value[index];
        }
    }
}
public class Type2IndexAdapter : ICanIndex
{
    public Type2 value;
    public Type2IndexAdapter(Type2 val)
    {
        this.value = val;
    }
    public string this[string index]
    {
        get
        {
            return this.value[index];
        }
    }
}
public class Type1 // ie SqlDataReader 
{
    public string this[string index]
    {
        get
        {
            Console.WriteLine("Type 1 indexer called: " + index);
            return null;
        }
    }
}

public class Type2 // ie DataRow 
{
    public string this[string index]
    {
        get
        {
            Console.WriteLine("Type 2 indexer called: " + index);
            return null;
        }
    }
}