Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用泛型类型约束强制Add方法存在_C#_Generics - Fatal编程技术网

C# 如何使用泛型类型约束强制Add方法存在

C# 如何使用泛型类型约束强制Add方法存在,c#,generics,C#,Generics,我有一个使用通用代码的代码: public static async Task<List<string>> GetDomainsAsync(IMemoryCache _cache) { return await ContextCache.CacheTryGetValueSet<List<String>>("SP_GET_DOMAINS", _cache); } public static async

我有一个使用通用代码的代码:

    public static async Task<List<string>> GetDomainsAsync(IMemoryCache _cache)
    {
        return await ContextCache.CacheTryGetValueSet<List<String>>("SP_GET_DOMAINS", _cache);
    }

    public static async Task<Dictionary<String, String>> GetSettingsAsync(IMemoryCache _cache)
    {
        return await ContextCache.CacheTryGetValueSet<Dictionary<String, String>>("SP_GET_SETTINGS", _cache);
    }
公共静态异步任务GetDomainsAsync(IMemoryCache\u缓存)
{
返回wait-wait-ContextCache.CacheTryGetValueSet(“SP_-GET_-DOMAINS”,_-cache);
}
公共静态异步任务GetSettingsAsync(IMemoryCache\u缓存)
{
返回wait-wait-ContextCache.CacheTryGetValueSet(“SP_-GET_-SETTINGS”,_-cache);
}
这是通用方法:

private static async Task<T> CacheTryGetValueSet<T>(String SPName, IMemoryCache _cache) where T : new()
{
          dynamic data = new T();


        ....

         while (reader.Read())
                                        {
                                            if (reader.FieldCount == 1)
                                            {
                                                data.Add(reader.GetString(0));
                                            }
                                            else if (reader.FieldCount == 2)
                                            {
                                                data.Add(reader.GetString(0), reader.GetString(1));
                                            }
                                        }
        ....

        return data;

        }
私有静态异步任务CacheTryGetValueSet(字符串SPName,IMemoryCache\u cache),其中T:new()
{
动态数据=新的T();
....
while(reader.Read())
{
如果(reader.FieldCount==1)
{
data.Add(reader.GetString(0));
}
else if(reader.FieldCount==2)
{
Add(reader.GetString(0),reader.GetString(1));
}
}
....
返回数据;
}
如何确保
T
实际上有一个
Add
方法?
可以添加什么泛型类型约束以确保只能传递IEnumerable?

您可以尝试使用
ICollection
接口作为泛型类型约束
,其中T:ICollection,new()

无法保证编译时泛型上有特定的方法,但是您可以强制泛型类型实现一个接口,比如具有Add方法的IList

public T Foo(),其中T:IList,new()
{
var list=newt();
添加(…);
退货清单;
}

每当您有一个包含
if(typeof(T))
的泛型方法时,您很可能做错了。泛型的全部要点是,它们对各种类型的操作完全相同。如果类型差异太大(例如,字典需要两个字段,而列表需要一个字段),您最终会在泛型方法中编写非泛型代码,这会使事情变得混乱

在这种情况下,您可能应该有两个方法,一个接受一个类型参数(返回
IEnumerable
,调用者可以轻松地将其转换为列表或在LINQ语句中使用),另一个接受两个类型参数(返回一个
IEnumerable
,调用者可以将其转换为字典或在LINQ中使用)

此外,当行变为可用时,您可能应该使用
yield return
,这样在调用者开始处理数据之前,您就不必读取整个行集。这将平滑您的性能,并巧妙地避免确定是否存在
Add()
方法的问题—您不需要它

下面是一个可以重写方法以解决这些问题的示例。这有点棘手,因为在
异步任务中,必须使用嵌套函数才能使用
产生返回值

public async Task<IEnumerable<TItem>> CacheTryGetValueSet<TItem>(string storedProcedureName, IMemoryCache cache)
{
    IEnumerable<TItem> Enumerate(SqlDataReader source)
    {
        while (source.Read())
        {
            yield return source.GetFieldValue<TItem>(0);
        }
    }

    var reader = await OpenReaderAsync(storedProcedureName);
    if (reader.FieldCount != 1) throw new ArgumentException("That type of cache doesn't return a single column.");
    return Enumerate(reader);
}

public async Task<IEnumerable<KeyValuePair<TKey,TValue>>> CacheTryGetValueSet<TKey,TValue>(string storedProcedureName, IMemoryCache cache)
{
    IEnumerable<KeyValuePair<TKey,TValue>> Enumerate(SqlDataReader source)
    {
        while (source.Read())
        {
            yield return new KeyValuePair<TKey, TValue>
            (
                source.GetFieldValue<TKey>(0),
                source.GetFieldValue<TValue>(1)
            );
        }
    }

    var reader = await OpenReaderAsync(storedProcedureName);
    if (reader.FieldCount != 2) throw new ArgumentException("That type of cache doesn't return two columns!");
    return Enumerate(reader);
}
公共异步任务CacheTryGetValueSet(string storedProcedureName,IMemoryCache缓存)
{
IEnumerable枚举(SqlDataReader源)
{
while(source.Read())
{
收益返回源.GetFieldValue(0);
}
}
var reader=wait OpenReaderAsync(storedProcedureName);
如果(reader.FieldCount!=1)抛出新的ArgumentException(“该类型的缓存不返回单个列”);
返回枚举(读卡器);
}
公共异步任务CacheTryGetValueSet(字符串存储的进程名称,IMemoryCache缓存)
{
IEnumerable枚举(SqlDataReader源)
{
while(source.Read())
{
返回新的KeyValuePair
(
source.GetFieldValue(0),
source.GetFieldValue(1)
);
}
}
var reader=wait OpenReaderAsync(storedProcedureName);
如果(reader.FieldCount!=2)抛出新的ArgumentException(“该类型的缓存不返回两列!”);
返回枚举(读卡器);
}
现在,调用方可以这样调用它:

public static async Task<List<string>> GetDomainsAsync(IMemoryCache _cache)
{
    return await ContextCache.CacheTryGetValueSet<string>("SP_GET_DOMAINS", _cache).ToList();
}

public static async Task<Dictionary<String, String>> GetSettingsAsync(IMemoryCache _cache)
{
    return await ContextCache.CacheTryGetValueSet<String, String>("SP_GET_SETTINGS", _cache).ToDictionary();
}
公共静态异步任务GetDomainsAsync(IMemoryCache\u缓存)
{
返回wait wait ContextCache.CacheTryGetValueSet(“SP_GET_DOMAINS”,_cache.ToList();
}
公共静态异步任务GetSettingsAsync(IMemoryCache\u缓存)
{
返回wait-wait-ContextCache.CacheTryGetValueSet(“SP_-GET_-SETTINGS”,_-cache).ToDictionary();
}

我尝试了此操作,这是我得到的错误:类型“System.Collections.Generic.List”不能用作泛型类型或方法“ContextCache.CacheTryGetValueSet”(字符串,IMemoryCache)中的类型参数“T”。没有从“System.Collections.Generic.List”到“System.Collections.Generic.ICollection”的隐式引用转换。
其中T:ICollection,new()
在这种情况下。不需要递归泛型定义。@StriplingWarrior ICollection不是IDictionary@realPro当前位置您需要对此进行详细说明。到目前为止,您所说的与
IDictionary
没有任何关系。您报告的例外情况是关于
列表
。我在对您的问题a的评论中问到关于第二个
Add
签名,但您尚未回答问题。如果您希望您的方法接受任何类似于泛型列表或字典的结构,则需要两个单独的方法签名,如果FieldCount与您提供的泛型类型不匹配,则仍有可能在运行时出现问题。@realPro在侮辱试图帮助你的人时,也许退后一步,意识到你的问题中实际上没有提到任何关于词典的内容(到目前为止,所有的回答都表明是IList/ICollection),你也没有回答OP a上的评论
public static async Task<List<string>> GetDomainsAsync(IMemoryCache _cache)
{
    return await ContextCache.CacheTryGetValueSet<string>("SP_GET_DOMAINS", _cache).ToList();
}

public static async Task<Dictionary<String, String>> GetSettingsAsync(IMemoryCache _cache)
{
    return await ContextCache.CacheTryGetValueSet<String, String>("SP_GET_SETTINGS", _cache).ToDictionary();
}