有没有任何方法可以在C#中传递函数引用而不指定结果类型
本文关键字:引用 类型 结果 传递函数 方法 任何 有没有 | 更新日期: 2023-09-27 18:27:28
我遇到了一个问题,我试图编写一个通用方法来读取xml并将数据写入数据库。
在这种情况下,数据是由程序的另一个副本序列化的。
在将xml中的项添加到SqlParameter之前,我需要通过实用程序文件中的几种不同的"修复"方法之一来运行它。
所需的特定方法是需要传入的东西,所以我最终将其作为字符串传入,并使用开关结构来确定调用哪个方法时将反射作为默认情况。
我想知道是否有任何方法可以真正传入方法引用,而不必指定它返回int、string、bool、decimal、double或DateTime。
我尝试过使用Func,但它需要一个结果类型。
新的论点可能看起来像:Tuple<string,Func<?>[] parameters
这些实用程序函数都将对象作为参数。
我发现了一个几乎是我想要的问题,除了他们没有一个可以完全不同的列表:
Func返回任意类型
我当前的代码:
private void SaveBundleToTable<T1, T2>
(
string xmlData,
string table,
string storedProcedure,
Tuple<string, string>[] parameters
)
where T1 : DataSet, new()
where T2 : DataRow
{
T1 BundleData = new T1();
BundleData.Clear();
StringReader theReader = new StringReader(xmlDataset);
BundleData.ReadXml(theReader);
foreach (T2 item in BundleData.Tables[table].Rows)
{
SqlCommand _cmd = new SqlCommand(storedProcedure, [SQLConnection]);
_cmd.CommandType = CommandType.StoredProcedure;
foreach (var par in parameters)
{
var _param = getSqlParameter<T2>(item, par.First, par.Second);
_cmd.Parameters.Add(_param);
}
_cmd.ExecuteNonQuery();
}
}
单独方法中的交换机结构:
private SqlParameter getSqlParameter<T>(T item, string columnName, string method) where T : DataRow
{
switch (method)
{
case "FixString":
return new SqlParameter(columnName, util.FixString(item[columnName]));
case "FixInt":
return new SqlParameter(columnName, util.FixInt(item[columnName]));
case "FixBooleanToInt":
return new SqlParameter(columnName, util.FixBooleanToInt(item[columnName]));
case "FixBoolean":
return new SqlParameter(columnName, util.FixBoolean(item[columnName]));
case "FixFloat":
return new SqlParameter(columnName, util.FixFloat(item[columnName]));
case "FixDouble":
return new SqlParameter(columnName, util.FixDouble(item[columnName]));
case "FixDate":
return new SqlParameter(columnName, util.FixDate(item[columnName]));
case "FixDateForZeroTime":
return new SqlParameter(columnName, util.FixDateForZeroTime(item[columnName]));
case "FixDecimal":
return new SqlParameter(columnName, util.FixDecimal(item[columnName]));
default:
try
{
Type thisType = util.GetType();
MethodInfo theMethod = thisType.GetMethod(method);
return new SqlParameter(columnName, theMethod.Invoke(this, new object[]{item[columnName]}));
}
catch (Exception ex)
{
throw new Exception("Unknown utility method: " + method,ex);
}
}
}
编辑1:
我只是尝试使用Tuple<string,Func<object,dynamic>>
的参数类型,但它不会编译,因为它说它无法确定Tuple<string,?>
的类型
注意,这个项目在.Net 3.5中,所以我实现了Tuple的本地版本,正如这个问题中所讨论的:
等效于.NET Framework 3.5 的Tuple(.NET 4)
编辑2:
如果我对泛型方法进行了更改,以便可以传递类型为Tuple<string,Func<object,object>>
的数组,那么当我尝试调用它时,我会在十进制行上得到一个编译错误:
new Tuple<string, Func<object,object>>[]
{
Tuple.New<string, Func<object,object>>("LAB_CODE",util.FixString),
Tuple.New<string, Func<object,object>>("MORM_SELL",util.FixDecimal),
...
如果我使用Tuple.New<string, Func<object,decimal>>
,则会出现更大的错误
您应该只有一个util。Fix(Object o)函数,通过确定代码来返回正确的修复
if (o is string) return util.FixString(o);
else if (o is int) return util.FixInt(o) ...
这与你所拥有的相似,但它清理了管理层。你的困境是,你被迫执行某种if语句,因为你对每个数据类型执行不同的逻辑。
对于类,只需创建一个接口,该接口具有为修复定义的必要方法。
你能简单地不使用Func<object, object>
吗?即使返回类型不是对象,我仍然可以编译它
public static string FixString(object data)
{
return null;
}
static void Main(string[] args)
{
DataRow row = null;
SqlParameter param = getSqlParameter(row, "Address", FixString);
}
private static SqlParameter getSqlParameter<T>(T item, string columnName, Func<object, object> method) where T : DataRow
{
return new SqlParameter(columnName, method(item[columnName]));
}
我确实找到了一种方法来实现函数传递,但对于我的情况来说,这太冗长了。
new Tuple<string, Func<object,object>>[]
{
Tuple.New<string, Func<object,object>>("LAB_CODE",util.FixString),
Tuple.New<string, Func<object,object>>("MORM_SELL",x => (object)util.FixDecimal(x)),
...
除非我能找到一种更简洁的方法,否则我想我会坚持我的switch语句
编辑:
我将这些函数添加到我的静态Tuple类中:
public static Tuple<string, Func<object, object>> Util<T>(string first, Func<object, T> second)
{
Func<object, object> method = getFunc<T>(second);
var tuple = new Tuple<string, Func<object, object>>(first, method);
return tuple;
}
private static Func<object,object> getFunc<T>(Func<object,T> method)
{
return x => (object)method(x);
}
这让我可以使用以下语法传入参数:
new Tuple<string, Func<object,object>>[]
{
Tuple.Util<string>("LAB_CODE",util.FixString),
Tuple.Util<decimal>("MORM_SELL",util.FixDecimal),
...
这些可以在扩展函数中实现,以便将其与.Net 4 Tuple类一起使用