有没有任何方法可以在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>> ,则会出现更大的错误

有没有任何方法可以在C#中传递函数引用而不指定结果类型

您应该只有一个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类一起使用