C# 如何正确实现泛型方法?

C# 如何正确实现泛型方法?,c#,linq,generics,C#,Linq,Generics,有人能帮我弄清楚如何通用地实现这个方法吗?编译器抱怨它无法解析t.Id。这是有道理的,但是,我如何告诉它所有通过的对象都有一个Id属性呢。以下是我为T定义的接口: namespace LiveWire.Model { public interface ILiveWireModel { Guid Id { get; } } } 所有存储库的接口: internal interface ILiveWireRepository<T> { I

有人能帮我弄清楚如何通用地实现这个方法吗?编译器抱怨它无法解析t.Id。这是有道理的,但是,我如何告诉它所有通过的对象都有一个Id属性呢。以下是我为T定义的接口:

namespace LiveWire.Model
{
    public interface ILiveWireModel
    {
        Guid Id { get; }
    }
}
所有存储库的接口:

internal interface ILiveWireRepository<T>
{
    ICacheProvider Cache { get; }
    string CacheKey { get; }

    SqlConnection CreateConnection();

    IEnumerable<T> GetData<TD>();

    IEnumerable<T> LoadData<TD>();

    Dictionary<Guid, T> GetCachedData<TD>();

    void ClearCache();
}
内部接口ILiveWireRepository
{
ICacheProvider缓存{get;}
字符串缓存键{get;}
SqlConnection创建连接();
IEnumerable GetData();
IEnumerable LoadData();
字典GetCachedData();
void ClearCache();
}
我的方法是:

public IEnumerable<T> GetData<TD>()
        where TD : ILiveWireModel
    {
        var data = GetCachedData<TD>();

        if (data == null)
        {
            data = LoadData<TD>().ToDictionary(t => t.Id);

            if (data.Any())
            {
                Cache.Set(CacheKey, data, 30);
            }
        }

        return data.Values;
    }
public IEnumerable GetData()
其中TD:ILiveWireModel
{
var data=GetCachedData();
如果(数据==null)
{
data=LoadData().ToDictionary(t=>t.Id);
if(data.Any())
{
Cache.Set(CacheKey,data,30);
}
}
返回数据值;
}
我把全班同学都包括进来,我希望他们能澄清一些事情

internal abstract class LiveWireRepositoryBase<T> : ILiveWireRepository<T>
{
    public ICacheProvider Cache { get; private set; }
    public string CacheKey { get; private set; }

    internal LiveWireRepositoryBase()
    {
        Cache = new DefaultCacheProvider();
    }

    public SqlConnection CreateConnection()
    {
        return new SqlConnection(
            ConfigurationManager
            .ConnectionStrings["LiveWire4Database"]
            .ConnectionString);
    }

    public IEnumerable<T> GetData<TD>()
        where TD : ILiveWireModel
    {
        var data = GetCachedData<TD>();

        if (data == null)
        {
            data = LoadData<TD>().ToDictionary(t => t.Id);

            if (data.Any())
            {
                Cache.Set(CacheKey, data, 30);
            }
        }

        return data.Values;
    }

    public IEnumerable<T> LoadData<TD>()
    {
        return new List<T>();
    }

    public Dictionary<Guid, T> GetCachedData<TD>()
    {
        throw new NotImplementedException();
    }


    public void ClearCache()
    {
        throw new NotImplementedException();
    }
}
内部抽象类LiveWireRepositoryBase:ILiveWireRepository
{
公共ICacheProvider缓存{get;private set;}
公共字符串缓存密钥{get;private set;}
内部LiveWireRepositoryBase()
{
缓存=新的DefaultCacheProvider();
}
公共SqlConnection CreateConnection()
{
返回新的SqlConnection(
配置管理器
.ConnectionString[“LiveWire4Database”]
.连接字符串);
}
公共IEnumerable GetData()
其中TD:ILiveWireModel
{
var data=GetCachedData();
如果(数据==null)
{
data=LoadData().ToDictionary(t=>t.Id);
if(data.Any())
{
Cache.Set(CacheKey,data,30);
}
}
返回数据值;
}
公共IEnumerable LoadData()
{
返回新列表();
}
公共字典GetCachedData()
{
抛出新的NotImplementedException();
}
公共void ClearCache()
{
抛出新的NotImplementedException();
}
}
我犯了一个我不明白的错误。我尝试使用显式接口实现,但最终我删除了where约束

方法“LiveWire.Data.Repositories.livewirepositorybase.GetData()”的类型参数“TD”的约束必须与接口方法“LiveWire.Data.Repositories.ilivewirepository.GetData()”的类型参数“TD”的约束匹配。请考虑使用显式接口实现。C:\projects\LiveWire\Solution\LiveWire.Data\Repositories\livewirepositorybase.cs 32 31 LiveWire.Data


您可以通过将类的签名更改为

public sealed class MyCache<T> where T : ILiveWireModel
公共密封类MyCache,其中T:ILiveWireModel
(或者,如果类位于不同的命名空间中,
其中T:LiveWire.Model.ILiveWireModel

也就是说,我不确定这种改变是否能解决你的问题。我只看到了您的项目代码的几个片段,因此我可能是错的,并对以下内容持保留态度:

将GUID键控值和整数键控值保持在同一缓存中真的是最好的设计吗?假设您从两个不同的源获取数据,一个使用GUID键,另一个使用整数键。但在将来,如果添加第三个源,它也使用整数键,会怎么样?来自两个整数密钥源的密钥可能会冲突,并且对于某些查询,缓存总是错误的。就我个人而言,我会在某个地方维护第二个表或函数(可能会为整数值键保留一个映射表,只需传递GUID值键),它知道从对象到键的映射,并在需要检查对象是否缓存时使用该函数。接下来的所有时间里,您的缓存都可以直接在键和值方面工作,而不必处理不同类型的键。

public IEnumerable GetData(),其中T:LiveWire.Model.ILiveWireModel{
public IEnumerable<T> GetData<T>() where T:LiveWire.Model.ILiveWireModel { 
  //.../

}
//.../ }

泛型的专门化。

您需要首先修复声明

public IEnumerable<T> GetData<T>()

在这个阶段得到的异常只是说接口定义

IEnumerable<T> GetData<TD>();

您需要在界面中添加相同的约束。

您尚未显示
LoadData
的定义。另外,
GetData
在这里不是泛型的,您需要
GetData()
而不是
GetData()
。投票结果是“向上”的-我不知道为什么投票结果是“向下”的,这对我来说似乎是一个合理的问题。@CAbbott好吧,缺少很多信息。由于这里的方法不是泛型的,所以它不会编译,原因与OP所说的完全不同,这意味着我们看不到他的真实代码。@Servy-True,但“请添加一些信息”注释可以修复这一问题。似乎有很多不必要的否决票在进行中。@cabbot你是说什么?直到这个相当糟糕的问题被提升,我才投反对票,但我当然不会批评任何人在没有评论的情况下对这个问题投反对票。我已经试过几次了,真的很关注它,但我没有看到积极的结果。编译器说,在执行以下操作时,不允许对非泛型声明使用约束:public IEnumerable GetData(),其中T:LiveWire.Model。ILiveWireModel@SteeleKennett这是因为你的“泛型”方法甚至不是泛型的。@正如你所评论的,我编辑并添加了前三行之后的所有内容。当然,这是一个共同的观点。@SteeleKennett看到了编辑,它指出了类的一个变化,可能会允许类编译。也就是说,请深入思考系统的设计。我在接下来的两段中指出了一些问题。@AdamMihalcin还有其他问题,比如,正如我所说的,他的方法不是通用的,LoadData也不是,所以即使是他的“黑客”也还有很长的路要走。我也同意他使用
动态
是不合适的,
public IEnumerable<T> GetData<T>() where T : ILiveWireModel
{
    var data = GetCachedData<T>();

    if (data == null)
    {
        data = LoadData<T>().ToDictionary(t => t.Id);

        if (data.Any())
        {
            Cache.Set(CacheKey, data, 30);
        }
    }

    return data.Values;
}
IEnumerable<T> GetData<TD>();
public IEnumerable<T> GetData<TD>() where TD : ILiveWireModel