作为一个例子,我将使用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。
编辑:我正在寻找一些合同执行,导致调用者传递实现所述索引器的对象。
答案 0 :(得分:7)
是对象吗?
差不多。没有可以使用的通用接口或类,因此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());
这允许您传入一个对象和一种机制来提取给定调用站点索引的值,该值适用于任何类型。
编辑方面:
编辑:我正在寻找一些合同执行,导致调用者传递实现所述索引器的对象。
没有这些类型实现的内置契约或接口,也没有任何基于索引器存在来约束泛型的方法。您将需要一种不同的方法,例如我建议使用委托来提取值。
答案 1 :(得分: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;
}
}
}