C# 我可以在ValueTuple中返回泛型类型吗?

C# 我可以在ValueTuple中返回泛型类型吗?,c#,generics,valuetuple,C#,Generics,Valuetuple,下面是一些示例代码。我收到错误“无法将类型'string'隐式转换为'T'” public ValueTuple TestMethod() { 返回(“测试”,“测试”); } 我该怎么做呢?这是否超出了ValueTuple的限制 我正在使用的真实代码示例 public ValueTuple<bool, T> RunSelectAllCommand<T>(MySqlCommand command, List<MySqlParameter> para

下面是一些示例代码。我收到错误“无法将类型'string'隐式转换为'T'”

public ValueTuple TestMethod()
{
返回(“测试”,“测试”);
}
我该怎么做呢?这是否超出了ValueTuple的限制

我正在使用的真实代码示例

public ValueTuple<bool, T> RunSelectAllCommand<T>(MySqlCommand command, 
    List<MySqlParameter> parameterCollection) where T : class
{
    using (MySqlConnection conn = new MySqlConnection(connectionString))
    using (var cmd = conn.CreateCommand())
    {
        conn.Open();            
        cmd.CommandText = command.CommandText;

        // if parameters for query are specified, add them here.
        if (parameterCollection != null)
        {
            cmd.Parameters.AddRange(parameterCollection.ToArray());
        }
        using (var reader = cmd.ExecuteReader())
        {
            // We're selecting all keys from registration database 
            // this is probably a horrible design. oh, well...
            if (typeof(T) == typeof(KeyRow))
            {
                List<KeyRow> data = new List<KeyRow>();
                while (reader.Read())
                {
                    data.Add(new KeyRow(reader["keycode"].ToString(), 
                        reader["apikey"].ToString(), 
                        reader["ipaddress"].ToString(),
                        DateTime.Parse(reader["date"].ToString()), 
                        reader["hwid"].ToString() ?? ""));
                }

                return (true, data as T);
            }
        }
    }

    return (false, null);
}
public ValueTuple RunSelectAllCommand(MySqlCommand),
列出参数集合),其中T:class
{
使用(MySqlConnection conn=newmysqlconnection(connectionString))
使用(var cmd=conn.CreateCommand())
{
conn.Open();
cmd.CommandText=command.CommandText;
//如果指定了查询的参数,请在此处添加它们。
if(parameterCollection!=null)
{
cmd.Parameters.AddRange(parameterCollection.ToArray());
}
使用(var reader=cmd.ExecuteReader())
{
//我们正在从注册数据库中选择所有密钥
//这可能是一个可怕的设计。哦,好吧。。。
if(typeof(T)=typeof(KeyRow))
{
列表数据=新列表();
while(reader.Read())
{
data.Add(新的KeyRow(读卡器[“keycode”])。ToString(),
读卡器[“apikey”].ToString(),
读卡器[“ipaddress”].ToString(),
Parse(读取器[“date”].ToString()),
读卡器[“hwid”].ToString()??“);
}
返回值(true,数据为T);
}
}
}
返回(false,null);
}

使用您的示例,我快速列出了以下示例,以说明如何执行您试图执行的操作。这使用了一个通用的实现方法来重用您可能返回的各种类型,一个非通用的方法来公开返回这些类型

public ValueTuple<bool, List<KeyRow>> RunSelectAllKeyRowCommand(IDbCommand command, List<IDataParameter> parameterCollection) =>
    RunSelectAllCommandImpl<KeyRow>(command, 
                                    parameterCollection,
                                    reader => new KeyRow(reader["keycode"].ToString(), reader["apikey"].ToString(), reader["ipaddress"].ToString(), DateTime.Parse(reader["date"].ToString()), reader["hwid"].ToString() ?? ""));

private ValueTuple<bool, List<T>> RunSelectAllCommandImpl<T>(IDbCommand command, List<IDataParameter> parameterCollection, Func<IDataReader, T> mapper) where T : class
{
    using (IDbConnection conn = GetDataConnection())
    using (var cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = command.CommandText;

        foreach(var parameter in parameterCollection) // if parameters for query are specified, add them here.
            cmd.Parameters.Add(parameter);

        using (var reader = cmd.ExecuteReader())
        {
            List<T> data = new List<T>();

            while (reader.Read())
                data.Add(mapper(reader));

            return (true, data);
        }
    }

    return (false, null);
}
public ValueTuple RunSelectAllKeyRowCommand(IDbCommand命令,列表参数集合)=>
运行SelectAllCommandImpl(命令,
参数收集,
reader=>newkeyrow(reader[“keycode”].ToString(),reader[“apikey”].ToString(),reader[“ipaddress”].ToString(),DateTime.Parse(reader[“date”].ToString()),reader[“hwid”].ToString();
private ValueTuple RunSelectAllCommandImpl(IDbCommand命令,列表参数集合,函数映射器),其中T:class
{
使用(IDbConnection conn=GetDataConnection())
使用(var cmd=conn.CreateCommand())
{
conn.Open();
cmd.CommandText=command.CommandText;
foreach(parameterCollection中的var参数)//如果指定了查询的参数,请将它们添加到此处。
cmd.Parameters.Add(参数);
使用(var reader=cmd.ExecuteReader())
{
列表数据=新列表();
while(reader.Read())
添加(映射器(读取器));
返回(真,数据);
}
}
返回(false,null);
}

这不是ValueTuple独有的。使用
publicttestmethod()=>string.Empty可以获得相同的行为为什么此方法需要是泛型的?它显然打算返回一个
ValueTuple
您希望如何将
string
转换为
T
并自动应用?您能将其设置为返回类型(string,object)吗?或者创建一个元组工厂,根据传递给它的枚举返回正确类型的元组?
public ValueTuple TestMethod()=>(string.Empty,default(T))在编译时没有问题。您遇到的问题是,当T不能保证是字符串时,试图使用字符串来代替T。@TomFarley返回
对象
通常是有问题的,因为调用者现在必须进行某种验证/转换才能将其转换为他们期望的类型。您可能应该返回类型为
T
的某个对象,而不是
object
。但是您在示例中使用泛型的方式没有任何意义,因为您没有接受任何类型为
t
的参数,也没有生成任何类型的参数。一个实际的例子可能会给你一个更好的答案。这是一个非常丰富的信息,并向我介绍了一些新概念,所以谢谢你。
return(false,null)永远不会到达。可以使用C#元组语法代替.NET类型,并且可以为元组值指定有意义的名称:
(bool,List data)
public ValueTuple<bool, List<KeyRow>> RunSelectAllKeyRowCommand(IDbCommand command, List<IDataParameter> parameterCollection) =>
    RunSelectAllCommandImpl<KeyRow>(command, 
                                    parameterCollection,
                                    reader => new KeyRow(reader["keycode"].ToString(), reader["apikey"].ToString(), reader["ipaddress"].ToString(), DateTime.Parse(reader["date"].ToString()), reader["hwid"].ToString() ?? ""));

private ValueTuple<bool, List<T>> RunSelectAllCommandImpl<T>(IDbCommand command, List<IDataParameter> parameterCollection, Func<IDataReader, T> mapper) where T : class
{
    using (IDbConnection conn = GetDataConnection())
    using (var cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = command.CommandText;

        foreach(var parameter in parameterCollection) // if parameters for query are specified, add them here.
            cmd.Parameters.Add(parameter);

        using (var reader = cmd.ExecuteReader())
        {
            List<T> data = new List<T>();

            while (reader.Read())
                data.Add(mapper(reader));

            return (true, data);
        }
    }

    return (false, null);
}