2016-01-10 215 views
2

如何调用泛型基类中抽象定义的函数。在泛型类C中调用类型参数的函数#

我具有从它派生像

Class2: Class1<Class2> 
Class3: Class1<Class3> 

通用类有3个功能

1-通用

class Class1<T> where T : class, new()

和多个类>接受动态对象和将所有的值放到相应的属性中,派生出对象

2->接受ID,查找数据库中的对应的行传递的动态对象的func1,并返回结果

3->它返回表中的所有行

这里是一个listall功能通用代码

public abstract partial class Class1<T> where T : class, new() 
{ 
    public static EntityLayout EntityLayout { get; protected set; } 

    [TypeAttributes(TypeAttributes.Options.IsPrimary, TypeAttributes.Options.IsAutoIncrement)] 
    /// <summary> Automatically Incremented 64 bit Integer Primary Key 
    /// represents the Unique ID of each row in Table </summary> 
    public long ID { get; set; } 
    /// <summary> Converts the row returned from Database to Object </summary> 
    /// <param name="row"></param> 
    /// <returns></returns> 
    public abstract T GetDetails(dynamic row); 
    public static T GetDetails(long ID) 
    { 
     var row = Shared.SessionWrapper.Current.globaldbcon.QuerySingle("SELECT * FROM [" 
      + EntityLayout.ContainerName + "].[" 
      + EntityLayout.TableName + "] WHERE [email protected]", ID); 
     if (row != null) return GetDetails(row); 
     return new T(); 
    } 
    public static List<T> ListAll() 
    { 
     List<T> result = new List<T>(); 
     foreach (var row in Shared.SessionWrapper.Current.globaldbcon.Query("SELECT * FROM [" 
      + EntityLayout.ContainerName + "].[" 
      + EntityLayout.TableName + "]")) result.Add(GetDetails(row)); 
     return result; 
    } 
} 

一个例子类实现

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using Arinsys.Database; 

namespace WebApplication1.Models 
{ 
    [EntityAttributes(EntityAttributes.Options.TestingEnabled)] 
    public class Class3 : Class1<Class3> 
    { 
     static Class3() 
     { 
      EntityLayout.DisplayName = "Users"; 
     } 
     /// <summary> User ID of the User </summary> 
     public long UID { get; set; } 
     /// <summary> User ID of the User if defined in Universal Data Store </summary> 
     public long UDSID { get; set; } 
     /// <summary> Login ID of User </summary> 
     public string LoginID { get; set; } 
     /// <summary> Registered email of the user. If not set will be set same as LoginID </summary> 
     public string Registeredemail { get; set; } 
     [TypeAttributes(TypeAttributes.Options.IsPassword)] 
     /// <summary> Password of user </summary> 
     public string Password { get; set; } 
     /// <summary> A Unique Security Stamp used for activation/deactivation of account or similar intense tasks </summary> 
     public string SecurityStamp { get; set; } 
     /// <summary> Timezone ID of the Default Timezone of User </summary> 
     public string DefaultTimezone { get; set; } 
     /// <summary> Current Status of User </summary> 
     public string CurrentStatus { get; set; } 
     /// <summary> Discriminator which defines the type of user in multi-user heirarchy scenario </summary> 
     public string UserType { get; set; } 
     /// <summary> Number of failed login attempts in total or same session depending upon configuration. Resets after Successful Login </summary> 
     public short FailedAttempts { get; set; } 
     /// <summary> Date Time of Last Failed Login Attempt in UTC </summary> 
     public DateTime LastFailedAttempt { get; set; } 
     /// <summary> Date Time of Last Successful Login in UTC </summary> 
     public DateTime LastLogin { get; set; } 
     /// <summary> Creation Date of User Account in UTC </summary> 
     public DateTime CreationDate { get; set; } 
     public override Class3 GetDetails(dynamic row) 
     { 
      Class3 result = new Class3(); 
      if (row != null) 
      { 
       result.ID = Convert.ToInt64(row.ID); 
       result.UID = Convert.ToInt64(row.UID); 
       result.UDSID = Convert.ToInt64(row.UDSID); 
       result.UserType = row.UserType; 
       result.LoginID = row.LoginID; 
       result.Password = row.Password; 
       result.Registeredemail = row.Registeredemail; 
       result.SecurityStamp = row.SecurityStamp; 
       result.DefaultTimezone = row.DefaultTimezone; 
       result.CurrentStatus = row.CurrentStatus; 
       result.FailedAttempts = Convert.ToInt16(row.FailedAttempts); 
       result.LastFailedAttempt = Convert.ToDateTime(row.LastFailedAttempt); 
       result.LastLogin = Convert.ToDateTime(row.LastLogin); 
       result.CreationDate = Convert.ToDateTime(row.CreationDate); 
      } 
      return result; 
     } 
    } 
} 

它已经两个星期搜索的在发布前到处回答,但无法找到解决方案。

我想要的就是ListAll函数应该调用第1个函数。由于它的抽象定义,我相信派生类必须有一个实现(即使它可能只是抛出NotImplementException,但实现保证)

我首先通过反射定义了泛型类中第一个函数的实现。虽然这种方式很有效,但速度很慢,在控制器动作开始/结束时通过启动/停止秒表进行性能基准测试,仅需100行就花了大约35秒,所以它肯定不适合生产用途。

注意事项

  • 静态不能定义抽象
  • 无法从静态上下文访问实例成员
  • 因业绩
  • 不能使用反射发出

可能的解决方案我猜是最接近(但我无法理解如何在我的情况下使用它们)

  • 转换的所有方法与实例方法和使用单
  • 使用接口
  • 定义在派生类中的静态方法和假设它会在那里的所有类,如果我走这条路再怎么对T访问静态方法在这种情况下

我想实现的是ListAll函数应该调用接受动态对象的第一个函数。

一些非常接近的问题是这些问题,但没有一个解决我的问题。

Stack Overflow Q1Stack Overflow Q2Stack Overflow Q3

+0

我对你的要求很不清楚。如果这就是你所追求的,你无法从同一类型的静态方法中调用实例方法。另外,我不会责怪反思,因为这段代码每秒只能处理3条记录,而那段时间很可能花费在查询数据库。 – CodeCaster

+0

看起来像你的'Class1 ',派生的是某种简单的映射器,对吗? –

+0

@IvanStoev是的。每个派生类将代表数据库中的一个表,基类将包含像CRUD操作这样的通用代码。我输入了大部分代码,只删除了与问题无关的部分。 –

回答

1

貌似设计应该是这样的

public abstract partial class Class1<T> where T : Class1<T>, new() 
{ 
    protected abstract void Load(dynamic row); 

    private static T GetItem(dynamic row) 
    { 
     var item = new T(); 
     if (row != null) 
      item.Load(row); 
     return item;   
    } 

    public static T GetDetails(long ID) 
    { 
     var row = Shared.SessionWrapper.Current.globaldbcon.QuerySingle("SELECT * FROM [" 
      + EntityLayout.ContainerName + "].[" 
      + EntityLayout.TableName + "] WHERE [email protected]", ID); 
     return GetItem(row); 
    } 

    public static List<T> ListAll() 
    { 
     List<T> result = new List<T>(); 
     foreach (var row in Shared.SessionWrapper.Current.globaldbcon.Query("SELECT * FROM [" 
      + EntityLayout.ContainerName + "].[" 
      + EntityLayout.TableName + "]")) result.Add(GetItem(row)); 
     return result; 
    } 
} 

和样品实施

public class Class3 : Class1<Class3> { 
{ 
    // ... 
    protected override void Load(dynamic row) 
    { 
     // No need to check for null, it is enforced by the base class 
     ID = Convert.ToInt64(row.ID); 
     UID = Convert.ToInt64(row.UID); 
     // ... 
    } 
} 

基本上你探索通过.NET泛型类的限制支持的Curiously recurring template patternT : Class1<T>)以确保派生类co包含摘要Load方法,而new T()部分由new()约束强制执行。

+0

我试过这个,但我得到相同的错误'T'不包含'负载'的定义,并且没有扩展方法'负载'接受类型'T'的第一个参数可以找到(你是否缺少使用指令或)\t Core \t C:\ Users \ Abhishek \ OneDrive \ Visual Studio Online Workspace \ Arinsys Library Collection \ Core \ Database \ DatabaseORM.cs –

+0

您是否更改了约束条件? –

+0

我道歉,我错过了。它现在有效。万分感谢。虽然我宁愿检查重写函数中的null,因为有可能该函数也可以从程序中的其他点调用。 –