使用索引器的存在作为方法的参数签名/合约/类型
本文关键字:参数 类型 方法 合约 索引 存在 | 更新日期: 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;
}
}
}