【问题标题】:The type cannot be used as type parameter in the generic type or method该类型不能用作泛型类型或方法中的类型参数
【发布时间】:2018-02-14 20:47:27
【问题描述】:

我有一个 DBHelper 类,我从中触发回调以将 IDataReader 转换为通用类型。我已经启动并运行了整个代码。但是,当我尝试在回调中创建该类型的实例时遇到了麻烦,应用了 where 子句 [参见 -> DataReaderToResultItemConverterCallback in class TestOneCallbacks]。

where 子句使它完美。 TResult 将是类型 TestOneResultItem。但是,我无法使用 where 子句来完成这项工作。或者,直接创建 TestTwoResultItem [See -> class TestTwoCallbacks] 并强制转换使其工作,但并不优雅。

这是 TestOneCallbacks 的以下错误,

类型“TResult”不能用作类型参数“TResult” 泛型类型或方法 'DataAccess.TestOneCallbacks.DataReaderToResultItemConverterCallback(System.Data.IDataReader)'。 没有装箱转换或类型参数转换 'TResult' 到 'Service.Interface.TestFilterResultItem'。

这里是代码。

public static class DBHelper
{
    public static List<TResult> ExecuteQuery<TResult>(DataQueryArgs<TResult> dataQueryArgs)
    {
        List<TResult> result = null;
        {
            IDataReader reader = null;

            //Get the input parameters for the query
            Dictionary<string, object> inputParameters = dataQueryArgs.InputParameters;

            //Fire callback to Get the DbCommand for the query
            DbCommand command = dataQueryArgs.GetCommandCallback();

            //Fire callback to Get the list of Sql input Parameters for the query
            List<SqlParameter> sqlParameters = dataQueryArgs.CreateSQLParametersCallback(inputParameters);

            //Execute the query and get an IDataReader object
            reader = ExecuteQuery(command, sqlParameters);

            //Fire callback Convert the IReader to ResultItem
            result = dataQueryArgs.DataReaderToResultItemConverterCallback(reader);
        }

        return result;
    }

    private static IDataReader ExecuteQuery(DbCommand command, List<SqlParameter> sqlParameters)
    {
        IDataReader reader = null;
        {
            //TODO:
        }

        return reader;
    }
}

class TestOneResultItem
{
    public TestOneResultItem()
    {
    }

    public string Name { get; set; }
    public int Age { get; set; }
    public DateTime DOB { get; set; }
}

class TestTwoResultItem
{
    public TestTwoResultItem()
    {
    }

    public string Description { get; set; }
    public int Size { get; set; }
}

public class TestOneCallbacks
{
    public DataQueryArgs<TResult> InitializeDataQueryCallbacks<TResult>(Dictionary<string, object> dataQueryArgs_inputParameters)
    {
        DataQueryArgs<TResult> args = null;
        DataQueryArgs<TResult>.DataReaderToResultItemConverter<TResult> dataReaderToResultItemConverterCallback = this.DataReaderToResultItemConverterCallback<TResult>;
        args = new DataQueryArgs<TResult>(dataReaderToResultItemConverterCallback);

        return args;
    }

    public List<TResult> DataReaderToResultItemConverterCallback<TResult>(IDataReader reader) where TResult : TestOneResultItem
    {
        List<TResult> results = new List<TResult>();
        TResult t1 = new TResult();     //Activator.CreateInstance ???
        {
            t1.Name = "ShaQ";
            t1.Age = 99;
            t1.DOB = DateTime.Now;
        }
        results.Add(t1);
        return results;
    }
}

public class TestTwoCallbacks
{
    public DataQueryArgs<TResult> InitializeDataQueryCallbacks<TResult>(Dictionary<string, object> dataQueryArgs_inputParameters)
    {
        DataQueryArgs<TResult> args = null;
        DataQueryArgs<TResult>.DataReaderToResultItemConverter<TResult> dataReaderToResultItemConverterCallback = this.DataReaderToResultItemConverterCallback<TResult>;
        args = new DataQueryArgs<TResult>(dataReaderToResultItemConverterCallback);

        return args;
    }

    public List<TResult> DataReaderToResultItemConverterCallback<TResult>(IDataReader reader) where TResult : TestTwoResultItem
    {
        var results = new List<TestTwoResultItem>();
        TestTwoResultItem t1 = new TestTwoResultItem();     //Activator.CreateInstance ???
        {
            t1.Description = "This works...";
            t1.Size = 345;
        }
        results.Add(t1);
        return results as List<TestTwoResultItem>;      //Ugly, but I know exactly what I am doing. This cast will succeed!
    }
}

【问题讨论】:

    标签: c# generics


    【解决方案1】:

    如果您将TResult 传递给该方法,则从调用方法派生的TResult 应该与被调用方法具有相同的类型约束。所以你必须在调用方法中添加类型约束where TResult : TestOneResultItemInitializeDataQueryCallbacks

    public DataQueryArgs<TResult> InitializeDataQueryCallbacks<TResult>
           (Dictionary<string, object> dataQueryArgs_inputParameters)
           where TResult : TestOneResultItem
    

    顺便说一句,为了调用TResult 构造函数,你需要new() 约束:

           where TResult : TestOneResultItem, new()
    

    【讨论】:

    • 这适用于该方法,但 InitializeDataQueryCallbacks() 的调用方法开始抛出相同的错误。当我沿着这条链前进时,我遇到了继承层次结构中的调用。正是对这个“接口”的调用从继承树中创建了必要的特定类型,并根据特定类型的 TResult (TestOneResultItem/TestTwoResultItem) 进行调用。 TResult 与此继承树中的特定类型具有 1-1 关系。
    • 虽然它并没有完全解决我的问题,但它帮助我实现了我所需要的。所以会接受这个。
    猜你喜欢
    • 2017-02-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-22
    • 1970-01-01
    相关资源
    最近更新 更多