访问通用实例属性

3
我该如何访问instanceId属性? 我有以下代码:
public void InsertOrUpdate(Book book)
{
    if (book.Id == default(int)) {

现在我想让它通用:

public class TheRepository<T> : IRepository<T> where T : class
{
    public void InsertOrUpdate(T instance)
    {
        if (instance.Id == default(int))//How can I access Id here
        {
            context.Set<T>().Add(instance);

我搜索了类似的帖子,我认为我应该写像 instance.GetType().GetProperty("Id").GetValue() 这样的东西,但我不知道具体如何操作?

2个回答

1
你可以这样进行hack。定义一个只有一个名为Id,类型为int的属性的接口:
interface IHaveId
{
    public int Id { get; set; }
}

接着声明你的实体实现了该接口:

public class Book : IHaveId

在您的通用存储库类中使用的类型应实现此接口。
public class TheRepository<T> : IRepository<T> where T : class, IHaveId
{
    public void InsertOrUpdate(T instance)
    {
        if (instance.Id == default(int))
        {
            context.Set<T>().Add(instance);
        }
    }
}

通过这样做,您可以避免使用反射,反射在一般情况下非常昂贵。此外,您的代码现在更加清晰。

我已经有一个名为IRepository的接口了,这是Entity Framework。而且我想将其应用于TheRepository而不是Book - user5032790
好的,我没有发现任何问题。我有误解什么吗?谢谢。 - Christos
你的意思是我应该将这个属性添加到现有的 IRepository 接口中还是创建一个新的接口? - user5032790
@user5032790,创建一个新接口并使实体继承它。 - Nkosi
我的意思是创建一个新的接口,应该由表示实体(如Book)的类来实现。基本上,后者意味着在每个实体类名称之后,您将附加此 :IHaveId,前提是每个实体都有一个名为 Id 的属性,这是实体的主键。然后,在 where 子句中,您只需在末尾添加此接口即可。请从我的答案开始阅读,如果有不清楚的地方,请让我知道,以便进行说明。谢谢! - Christos
显示剩余3条评论

0

目前,编译器除了知道 T 是一个类以外一无所知。这意味着它永远不会知道它有一个 Id 属性,因为你可以创建一个 TheRepository<string> 实例 - 当然,这个实例没有 Id 属性。

你在回答中提到的代码片段,使用反射,不是一个好方法。如果像我之前提到的那样,你创建了一个字符串存储库,会发生什么?这段代码必然会失败,因为字符串没有 Id 属性。

在这种情况下,你需要做的是确保 Book 类,以及任何其他需要保存在存储库中的实体,都实现一个包含 ID 的基类:

public abstract class DataObject
{
    public int Id {get;set;}
}

public class Book : DataObject
{}

现在,您可以将代码库限制为继承 DataObject 的类:

public class TheRepository<T> : IRepository<T> where T : DataObject

现在,编译器可以确信,无论T是什么,任何T的实例都会继承DataObject,因此具有一个Id属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接