4

例如,我将使用 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。

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

4

2 回答 2

7

是对象吗?

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

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

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

但是,除了通过反射之外,传入 asobject不会提供对索引器的访问。

执行此操作的唯一直接方法是 via 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());

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


编辑关于:

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

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

于 2013-05-17T18:36:01.120 回答
1

我会说 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;
        }
    }
}
于 2013-05-17T18:51:06.440 回答