gpt4 book ai didi

c# - 在泛型类 C# 中调用类型参数的函数

转载 作者:太空宇宙 更新时间:2023-11-03 12:53:36 24 4
gpt4 key购买 nike

我们如何调用在泛型基类中定义为抽象的函数。

我有一个通用的

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

以及从它派生的多个类

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

泛型类有3个函数

1->接受一个动态对象,并将所有值放入派生对象中的相应属性

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 ID=@0", 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 函数应该调用第一个函数。因为它是抽象定义的,所以我确信派生类必须有一个实现(即使它可能只是抛出 NotImplementException,但实现是有保证的)

我首先通过反射在泛型类本身中定义了第一个函数的实现。虽然这行得通,但速度非常慢,通过在 Controller Action 开始/结束时启动/停止秒表来进行性能基准测试,仅 100 行就花费了大约 35 秒,因此它肯定不适合生产使用。

注意事项

  • 静态不能定义为抽象
  • 无法从静态上下文访问实例成员
  • 由于性能问题不能使用反射

我想可能的解决方案最接近(但我无法理解如何在我的案例中使用它们)

  • 将所有方法转换为实例方法并使用单例
  • 使用接口(interface)
  • 在派生类中定义一个静态方法并假设它会存在于所有类中,如果我这样做那么在这种情况下如何访问 T 上的静态方法

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

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

Stack Overflow Q1 Stack Overflow Q2 Stack Overflow Q3

最佳答案

看起来设计应该是这样的

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 ID=@0", 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);
// ...
}
}

基本上你探索Curiously recurring template pattern .NET 泛型类约束 (T : Class1<T>) 支持以确保派生类包含抽象 Load方法,而 new T()部分由 new() 强制执行约束条件。

关于c# - 在泛型类 C# 中调用类型参数的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34705244/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com