如何使派生类使用基类的属性?

时间:2013-11-22 06:25:42

标签: c# generics inheritance linq-to-sql expression

一般的想法从创建一个控件开始,该控件适用于任何数据库对象。 通过LINQ to SQL访问数据库,并从现有数据库自动生成数据库对象。

为了使控件能够与这些对象中的任何一个一起使用,我使用了一个基本接口,所有自动生成的对象都从该接口继承。因此控件实际上适用于该界面。

此界面首先应提供:

  1. 获取对象的标识符(主键)的能力
  2. 一个表达式,如果通过对象实例编译和调用,将返回此标识符
  3. 所以这看起来像:

    public interface IEntity<TEntity, TEntityId>
        where TEntity : IEntity<TEntity, TEntityId>
        where TEntityId : IEquatable<TEntityId>
    {
        Expression<Func<TEntity, TEntityId>> GetIdExpression();
        TEntityId EntityId { get; }
    }
    

    然后数据库对象的类定义如下:

    //let it be the auto-generated part:
    public partial class Entity1
    {
        public Guid UId { get; set; }
    }
    //and the manual part:
    public partial class Entity1 : IEntity<Entity1, Guid>
    {
        public Expression<Func<Entity1, Guid>> GetIdExpression()
        {
            return (Expression<Func<Entity1, Guid>>)(se => se.UId);
        }
        public Guid EntityId
        {
            get { return this.UId; }
        }
    }
    

    我们可以测试一下:

    var e1 = new Entity1();
    e1.UId = Guid.NewGuid();
    Console.WriteLine(e1.UId); 
    Console.WriteLine(e1.GetIdExpression().Compile()(e1));
    

    这两条线的输出相等。没关系。

    下一个想法是,所有数据库对象的狮子份额都有int标识符,名称为Id。最好避免编辑每一个,即不要编写实现IEntity<TEntity, TEntityId>的同一个代码。

    至于我需要指定这个接口的实现,我需要一个类。 现在我最终得到了

    public class IntEntity<TEntity> : IEntity<TEntity, int>
           where TEntity : IntEntity<TEntity>
    {
        public int Id { get; set; }
    
        public Expression<Func<TEntity, int>> GetIdExpression()
        {
            return (Expression<Func<TEntity, int>>)(e => e.Id);
        }
    
        public int EntityId
        {
            get { return this.Id; }
        }
    }
    

    然后数据库对象类将从中派生出来:

    //let it be the auto-generated part:
    public partial class Entity2
    {
        public int Id { get; set; }
    }
    //and the manual part:
    public partial class Entity2 : IntEntity<Entity2>
    {
    }
    

    现在很明显,Id中的Entity2确实隐藏了Id中的IntEntity<TEntity>。同样的测试也证明了这一点:

    var re = new Entity2();
    re.Id = 5;
    Console.WriteLine(re.Id); //5
    Console.WriteLine(re.GetIdExpression().Compile()(re)); //0
    

    所以这个解决方案错了...... 我还尝试将IntEntity<TEntity>抽象化,但显然失败了,因为Entity2 Id在自动生成的部分中已定义,而我无法使override成为{基类的{1}} abstract

    我能做些什么来使Id的所有数据库对象都使用基础int Id类中的Id。或者,可能反过来......

    这里的要点是IntEntity<TEntity>返回的表达式应该具有GetIdExpression形式,因为此表达式稍后将用于LINQ to SQL查询,因此LINQ应该能够将其转换为一个正确的SQL查询。

1 个答案:

答案 0 :(得分:0)

我不确定这正是你想要的,但你可以尝试这样做

public abstract class IntEntity<TEntity> : IEntity<TEntity, int>
   where TEntity : IntEntity<TEntity>
{
    public abstract Expression<Func<TEntity, int>> GetIdExpression();
    public abstract int EntityId
    {
        get;
    }
}

public partial class Entity2
{
    public int Id { get; set; }
}
//and the manual part:
public partial class Entity2 : IntEntity<Entity2>
{
    public override int EntityId
    {
        get { return this.Id; }
    }

    public override Expression<Func<Entity2, int>> GetIdExpression()
    {
        return (Expression<Func<TEntity, int>>)(e => e.Id);
    }
}

实际上没有override virtual您无法从基类中的方法访问derive类中的字段
事实上,上面的样本等于你的第一个样本

<强>更新

作为解决方法,您可以添加方法SetId,它在derive和base类中设置id,就像这样

public class IntEntity<TEntity> : IEntity<TEntity, int>
   where TEntity : IntEntity<TEntity>
{
    public int Id { get; set; }

    public Expression<Func<TEntity, int>> GetIdExpression()
    {
        return (Expression<Func<TEntity, int>>)(e => e.Id);
    }

    public int EntityId
    {
        get { return this.Id; }
    }
}

//let it be the auto-generated part:
public partial class Entity2
{
    public int Id { get; set; }
}
//and the manual part:
public partial class Entity2 : IntEntity<Entity2>
{
    public void SetId(int id)
    {
        Id = id;
        base.Id = id;
    }
}

var re = new Entity2();
re.SetId(5);
Console.WriteLine(re.Id); //5
Console.WriteLine(re.GetIdExpression().Compile()(re)); //5