C# 有没有更好的办法?

C# 有没有更好的办法?,c#,C#,我真的不知道该在标题里写什么,所以不要读太多 不管怎么说,要解释我遇到的麻烦是这个。我有三个类:A、B和C。类的层次结构如下: Connection.RunUpdateQuery(..., CreateTable<TableC>(Utility.ToDictionary(Entry))); //only fields of TableC will be passed along. A您可能应该使用ORM库,如EntityFramework或NHibernate。他们知道如何处理继承

我真的不知道该在标题里写什么,所以不要读太多

不管怎么说,要解释我遇到的麻烦是这个。我有三个类:A、B和C。类的层次结构如下:

Connection.RunUpdateQuery(..., CreateTable<TableC>(Utility.ToDictionary(Entry))); //only fields of TableC will be passed along.

A您可能应该使用ORM库,如EntityFramework或NHibernate。他们知道如何处理继承(他们提供了几种可供选择的策略)。那么您根本不需要编写任何样板代码。

您说您正在使用反射。在这种情况下,执行以下操作:

C myObject = new C();    
myObject.GetType().GetProperties(System.Reflection.BindingFlags.Public 
                | System.Reflection.BindingFlags.Instance 
                | System.Reflection.BindingFlags.DeclaredOnly)
应该只提供在
C
中特别声明的属性,而不是在
B
A
中声明的属性。从那时起,您可以使用
myObject.GetType().BaseType
,它将为您提供
B
,并且它的
BaseType
将是
A

我在这里制作了一个粗略的查询生成器:,它生成所有需要的更新查询(如果您传递a
C
,它将生成表
a
B
C
)的查询,但作为参数传递的类型除外

有了这些信息,您就可以轻松地动态地为任何层次结构生成更新查询

我会给你更具体的代码,但你一个也没写

并不是说这是一个完美的解决方案,但这正是您在问题中所要求的

我想典型的C#解决方案是用自定义属性标记字段,并在反思中使用它来决定是否应该包含它

public class DoSerializeAttribute : Attribute {} 

public class C : B {
    [DoSerialize]
    public MyMember { get; set; }
}
然后在反射代码中,您可以使用方法。

不必学习ORM(这是一件正确的事情,但在一个简单的情况下可能有点过火,我说的过火是指学习曲线),您可以使用LINQ to SQL作为模型来访问数据,而不是自己创建
C
类。创建
dbml
文件(例如,关于它是什么,请参见)。结果生成了表类代码,然后就可以使用它了

using (var context = new SomeContext()) // static connection string
{
    var query = context.SomeTable.AsQueryable();
    if (SelectedFilter == Today)
        query = query.Where(o => o.Id >= DateTime.Today);
    ...
    // constructing ViewModel items (WPF, MVVM)
    foreach (var item in query)
        items.Add(new Item()
        {
            Id = item.Id,
            ...
        }
}
Item
B
在您的示例中)是一个保存值的简单类。您可以使用另一个查询或上下文(另一个表或数据库)填充
项的其他属性

当您想要更新数据库时,只需执行以下操作

using (var context = new SomeContext())
{
    var change = context.SomeTable.First(o => o.Id == item.Id);
    change.Comment = item.Comment;
    ...
    context.SubmitChanges();
}
基本上,您只需为现成的ViewModel项编写一次这些方法(可能是对多个表的复杂查询,也可能是对不同数据库的多个查询)。更新部分可以是
的方法,或者更好的方法是ViewModel的方法(因为它可以优化,例如,当只更改
注释
时,您不需要更新其他字段和执行其他查询)


样板?不是真的,查看一下
SomeContext
生成的cs文件来查看一些。

坦率地说,我个人认为您当前的解决方案是一团糟。对于这类东西,有大量的工具可供使用,为什么要重新发明(老实说是非常糟糕的)轮子呢

无论如何,为了解决您在特定设置中遇到的问题,我会这样做:

首先,摆脱继承。你根本不应该用它。Inheritante绝对不是用来避免数据重复的工具,简单的概念是可怕的

在数据库中有两个不同的表,对它们进行编码

  • DbType
  • PumpEntry
  • 我不知道您为什么需要中间
    SignalEntryD
    。如果它不是数据库中的一个表,那么它不应该出现在代码中的任何地方(我猜这也是由于代码重复)

    保持一致:如果字段
    Channel
    pCoeNum
    在数据库中的不同表中重复,则只需在实体中重复它们即可。否则,请在数据库中创建一个表,然后在实体中对其进行建模(就像使用
    DbType
    )。不要把事情搞混了,两头都用同样的方法做

    出于稍后将变得清晰的原因,请让您的实体实现一个“虚拟”接口
    ITable
    (类型安全)和一个默认的无参数构造函数(当然包括您的所有属性/字段)

    现在的问题是,如果我理解正确的话,您正在接收一个带有用户更新值的
    字典
    ,您需要更新给定的表,问题是dicitonary可以包含属于不同表的字段(我不会从一开始就讨论您是如何解决这个问题的,我将继续…)

    那么,只需创建一种使用反射从随机dictionary构建任何实体的方法(我的代码使用属性,但它与字段等效):

    public static T CreateTable(IDictionary值),其中T:ITable,new()
    {
    var table=newt();
    foreach(typeof(T).GetProperties()中的var propInfo)
    {
    if(values.ContainsKey(propInfo.Name))
    {
    SetValue(表,值[propInfo.Name]);
    }
    }
    return table;//请注意,字典中未定义的任何属性都将初始化为字段的类型默认值。
    }
    
    现在,您可以按如下方式使用它:

    Connection.RunUpdateQuery(..., CreateTable<TableC>(Utility.ToDictionary(Entry))); //only fields of TableC will be passed along.
    
    Connection.RunUpdateQuery(…,CreateTable(Utility.ToDictionary(Entry))//只传递TableC的字段。
    
    我听说C#没有多重继承,这是一个非常适合此工作的工具
    您可以使用
    接口
    。一个类可以实现多个接口。您希望获得类
    C
    的成员,这些成员不是从类
    A
    B
    继承的?在我看来,直接处理数据库在您的情况下不是一个好的解决方案。请考虑使用ORM,如实体框架或NHiBiNATE。我无法看到类型层次结构背后的推理。当您开始遇到与您类似的问题时,“我希望派生的成员不是Base的一部分”,这通常意味着继承可能不是工作的最佳工具。可能是接口或“has a”而不是“is a”关系
    using (var context = new SomeContext())
    {
        var change = context.SomeTable.First(o => o.Id == item.Id);
        change.Comment = item.Comment;
        ...
        context.SubmitChanges();
    }
    
    public static T CreateTable<T>(IDictionary<string, object> values) where T: ITable, new()
    {
         var table = new T();
    
         foreach (var propInfo in typeof(T).GetProperties())
         {
              if (values.ContainsKey(propInfo.Name))
              {
                   propInfo.SetValue(table, values[propInfo.Name]);
              }
         }
    
         return table; //note that any property not defined in the dictionary will be initialized to the field's type default value.
    }
    
    Connection.RunUpdateQuery(..., CreateTable<TableC>(Utility.ToDictionary(Entry))); //only fields of TableC will be passed along.