如何使用反射在.net中的静态超类函数中获取子类类型对象?

如何使用反射在.net中的静态超类函数中获取子类类型对象?,.net,generics,reflection,inheritance,repository,.net,Generics,Reflection,Inheritance,Repository,好的,所以我尝试为数据访问对象创建一个好的超类,它可以生成一个tsql查询来搜索子类的所有公共字符串属性。我想使用反射获取子类的类型,然后遍历对象上的所有公共字符串属性,因为这些属性名称与数据库列名相同。然后,我可以使用这些属性名生成tsql查询 [警告:嘿,我宁愿使用nhibernate,但我无法说服这些人使用它] [我也可以用泛型解决这个问题,但我认为他们觉得泛型很可怕,因为他们是VB.net的家伙,如果我伤害了你的感情,请原谅VB.net偷窥;] 那么基本对象是这样的: public ab

好的,所以我尝试为数据访问对象创建一个好的超类,它可以生成一个tsql查询来搜索子类的所有公共字符串属性。我想使用反射获取子类的类型,然后遍历对象上的所有公共字符串属性,因为这些属性名称与数据库列名相同。然后,我可以使用这些属性名生成tsql查询

[警告:嘿,我宁愿使用nhibernate,但我无法说服这些人使用它]

[我也可以用泛型解决这个问题,但我认为他们觉得泛型很可怕,因为他们是VB.net的家伙,如果我伤害了你的感情,请原谅VB.net偷窥;]

那么基本对象是这样的:

public abstract class RepositoryBase
{
   public static IList<RepositoryBase> Search()
   {
        //get all public properties of the inheriting subclass
        // I already have the rest of the search code
   }
}
这是可能的,还是可取的

当我打这个的时候,我想去他妈的,我会用泛型来做


谢谢你的阅读

我认为大多数存储库模式使用接口,而不是像这样的抽象类

 public class SqlRepository : IRepository {

        DB _db;

        public SqlRepository(DB dataContext) {
            //override the current context
            //with the one passed in
            _db = dataContext;

        } 

        public IQueryable<RepositoryBase> Search() {

           ...
我想我从来没有见过这样写的模式。我想这是可能的,但我不认为你能完成你认为你正在努力完成的事情。看看


有什么原因不能使用接口吗?

我认为大多数存储库模式使用接口,而不是像这样的抽象类

 public class SqlRepository : IRepository {

        DB _db;

        public SqlRepository(DB dataContext) {
            //override the current context
            //with the one passed in
            _db = dataContext;

        } 

        public IQueryable<RepositoryBase> Search() {

           ...
我想我从来没有见过这样写的模式。我想这是可能的,但我不认为你能完成你认为你正在努力完成的事情。看看


有什么理由不能改用接口吗?

好吧,假设您仍然想要一个答案:没有。在静态方法中,您不在对象的上下文中。如果不构造StackTrace,您就不知道是谁调用了您,即使您这样做了,您也不知道调用方是应该为其枚举属性的对象


如果它是一个实例方法,您可以只调用GetType。

好吧,假设您仍然想要一个答案:否。在静态方法中,您不在对象的上下文中。如果不构造StackTrace,您就不知道是谁调用了您,即使您这样做了,您也不知道调用方是应该为其枚举属性的对象


如果它是一个实例方法,您可以只调用GetType。

当您通过派生类调用静态方法时,编译器解析该方法,使IL实际包含基类。例如:

public class Base
{
    static void Foo() {}
}

public class Derived : Base {}

class Test
{
    static void Main()
    {
        Derived.Foo();
    }
}
Main中的调用实际上在IL中编译为Base.Foo,至少在从C编译时是这样。因此,在执行时,您无法判断原始调用是什么


听起来泛型是一种方法。

当您通过派生类调用静态方法时,编译器会解析该方法,因此IL实际上包含基类。例如:

public class Base
{
    static void Foo() {}
}

public class Derived : Base {}

class Test
{
    static void Main()
    {
        Derived.Foo();
    }
}
Main中的调用实际上在IL中编译为Base.Foo,至少在从C编译时是这样。因此,在执行时,您无法判断原始调用是什么


听起来泛型是一个不错的选择。

我只是在用VB处理你提出的问题。 此代码从西班牙语翻译而来,因此可能包含拼写错误: 例如,它可以这样使用:

Public Sub Main()
   'the SELEC method used below this line is written once and called from every table/class'
   Dim CustList As List(Of CUSTOMER) = CUSTOMER.SELEC("Name = 'Peter'", "Name DESC")
   Dim myOrders As List(Of ORDER) = CustList(0).Orders
   CustList(0).Name = "John"
End Sub


Public Interface ITables 'used solely to unify all the table types'
    '    ReadOnly Property PrimaryKey() As String is better to shadow it from SuperClass TableType'
End Interface

Public Class TableType(Of T As ITables)'this T is what you are looking for'
    Public PrimaryKey As String
    Public Shared Function SELEC(Optional ByVal sWhere As String = "", Optional ByVal sOrderBy As String = "") As List(Of T)
        'shared/static method to fill and return a typed List with the DB rows'
        'can be called using for example Type.SELEC()'
        Dim oConn As New OdbcConnection(My.Settings.ConnectionString)
        Dim oComm As OdbcCommand = oConn.CreateCommand
        oComm.CommandText = "SELECT * FROM " & GetType(T).Name
        If sWhere.Length > 0 Then oComm.CommandText &= " WHERE " & sWhere
        If sOrderBy.Length > 0 Then oComm.CommandText &= " ORDER BY " & sOrderBy
        Dim oListRet As New List(Of T)
        oConn.Open()
        Dim oDR As OdbcDataReader = oComm.ExecuteReader
        Dim oneRow As T
        Do While oDR.Read
            oneRow = Activator.CreateInstance(GetType(T))
            For i = 0 To oDR.FieldCount - 1
                Dim value = oDR.Item(i)
                If TypeOf value Is DBNull Then value = Activator.CreateInstance(oDR.GetFieldType(i)) ' default value'
                oneRow.GetType.GetProperty(oDR.GetName(i)).SetValue(oneRow, value, Nothing)
            Next
            oListRet.Add(oneRow)
        Loop
        oDR.Close()
        oConn.Close()
        oConn.Dispose()
        Return oListRet
    End Function

    Public Function UPDATE(Optional ByVal sWhere As String = "") As Integer
        'not shared but one for all tables'
        'working on this, almost finished'
    End Function
    Shared Function fnPropAttribute(ByVal oProp As PropertyInfo, ByVal sAttrName As String) As String
        'working on this. Returns for example the value of the attribute 'Category' of a field'
        Dim attributes As AttributeCollection = TypeDescriptor.GetProperties(oProp.DeclaringType)(oProp.Name).Attributes
        Dim myAttribute As CategoryAttribute = CType(attributes(GetType(need to know wth to put here)), CategoryAttribute)
        Return myAttribute.Category
    End Function
End Class 'TableType'


Public Class Tables
    Public Class CUSTOMER
        Inherits TableType(Of CUSTOMER)
        Implements ITables
        Public Shadows Const PrimaryKey As String = "idCust"

        'this returns the List(Of Orders) with my idCust'
        Public ReadOnly Property ORDERs() As List(Of ORDER)
            Get
                Return ORDER.SELEC("idCust = " & Me.idCust)
            End Get
        End Property

        Dim _idCust As Integer

        'this Attributes will be used in UPDATE, INSERT, etc'
        'Category 'Columns' is to distingish between DB fields and other possible properties'
        'Description is the ODBCType of the field'
        <Category("Columns"), Description("CHAR")> _
        Public Property idCust() As Integer
            Get
                Return _idCust
            End Get
            Set(ByVal value As Integer)
                _idCust = value
            End Set
        End Property

        Dim _Name As String
        <Category("Columns"), Description("CHAR")> _
        Public Property Name() As String
            Get
                Return _Name
            End Get
            Set(ByVal value As String)
                _Name = value
            End Set
        End Property
        'etc...'
    End Class 'Customer'
    Public Class ORDER
        Inherits TableType(Of ORDER)
        Implements ITables
        Public Shadows Const PrimaryKey As String = "idOrder"

        Dim _idOrder As Integer
        <Category("Columns"), Description("CHAR")> _
        Public Property idOrder() As Integer
            Get
                Return _idOrder
            End Get
            Set(ByVal value As Integer)
                _idOrder = value
            End Set
        End Property

        Dim _idCust As Integer
        <Category("Columns"), Description("CHAR")> _
        Public Property idCust() As Integer
            Get
                Return _idCust
            End Get
            Set(ByVal value As Integer)
                _idCust = value
            End Set
        End Property

        Dim _Artic As String
        <Category("Columns"), Description("CHAR")> _
        Public Property Artic() As String
            Get
                Return _Artic
            End Get
            Set(ByVal value As String)
                _Artic = value
            End Set
        End Property
        'etc...'
    End Class 'Order'
End Class 'Tables'

我只是在按照你的建议工作。 此代码从西班牙语翻译而来,因此可能包含拼写错误: 例如,它可以这样使用:

Public Sub Main()
   'the SELEC method used below this line is written once and called from every table/class'
   Dim CustList As List(Of CUSTOMER) = CUSTOMER.SELEC("Name = 'Peter'", "Name DESC")
   Dim myOrders As List(Of ORDER) = CustList(0).Orders
   CustList(0).Name = "John"
End Sub


Public Interface ITables 'used solely to unify all the table types'
    '    ReadOnly Property PrimaryKey() As String is better to shadow it from SuperClass TableType'
End Interface

Public Class TableType(Of T As ITables)'this T is what you are looking for'
    Public PrimaryKey As String
    Public Shared Function SELEC(Optional ByVal sWhere As String = "", Optional ByVal sOrderBy As String = "") As List(Of T)
        'shared/static method to fill and return a typed List with the DB rows'
        'can be called using for example Type.SELEC()'
        Dim oConn As New OdbcConnection(My.Settings.ConnectionString)
        Dim oComm As OdbcCommand = oConn.CreateCommand
        oComm.CommandText = "SELECT * FROM " & GetType(T).Name
        If sWhere.Length > 0 Then oComm.CommandText &= " WHERE " & sWhere
        If sOrderBy.Length > 0 Then oComm.CommandText &= " ORDER BY " & sOrderBy
        Dim oListRet As New List(Of T)
        oConn.Open()
        Dim oDR As OdbcDataReader = oComm.ExecuteReader
        Dim oneRow As T
        Do While oDR.Read
            oneRow = Activator.CreateInstance(GetType(T))
            For i = 0 To oDR.FieldCount - 1
                Dim value = oDR.Item(i)
                If TypeOf value Is DBNull Then value = Activator.CreateInstance(oDR.GetFieldType(i)) ' default value'
                oneRow.GetType.GetProperty(oDR.GetName(i)).SetValue(oneRow, value, Nothing)
            Next
            oListRet.Add(oneRow)
        Loop
        oDR.Close()
        oConn.Close()
        oConn.Dispose()
        Return oListRet
    End Function

    Public Function UPDATE(Optional ByVal sWhere As String = "") As Integer
        'not shared but one for all tables'
        'working on this, almost finished'
    End Function
    Shared Function fnPropAttribute(ByVal oProp As PropertyInfo, ByVal sAttrName As String) As String
        'working on this. Returns for example the value of the attribute 'Category' of a field'
        Dim attributes As AttributeCollection = TypeDescriptor.GetProperties(oProp.DeclaringType)(oProp.Name).Attributes
        Dim myAttribute As CategoryAttribute = CType(attributes(GetType(need to know wth to put here)), CategoryAttribute)
        Return myAttribute.Category
    End Function
End Class 'TableType'


Public Class Tables
    Public Class CUSTOMER
        Inherits TableType(Of CUSTOMER)
        Implements ITables
        Public Shadows Const PrimaryKey As String = "idCust"

        'this returns the List(Of Orders) with my idCust'
        Public ReadOnly Property ORDERs() As List(Of ORDER)
            Get
                Return ORDER.SELEC("idCust = " & Me.idCust)
            End Get
        End Property

        Dim _idCust As Integer

        'this Attributes will be used in UPDATE, INSERT, etc'
        'Category 'Columns' is to distingish between DB fields and other possible properties'
        'Description is the ODBCType of the field'
        <Category("Columns"), Description("CHAR")> _
        Public Property idCust() As Integer
            Get
                Return _idCust
            End Get
            Set(ByVal value As Integer)
                _idCust = value
            End Set
        End Property

        Dim _Name As String
        <Category("Columns"), Description("CHAR")> _
        Public Property Name() As String
            Get
                Return _Name
            End Get
            Set(ByVal value As String)
                _Name = value
            End Set
        End Property
        'etc...'
    End Class 'Customer'
    Public Class ORDER
        Inherits TableType(Of ORDER)
        Implements ITables
        Public Shadows Const PrimaryKey As String = "idOrder"

        Dim _idOrder As Integer
        <Category("Columns"), Description("CHAR")> _
        Public Property idOrder() As Integer
            Get
                Return _idOrder
            End Get
            Set(ByVal value As Integer)
                _idOrder = value
            End Set
        End Property

        Dim _idCust As Integer
        <Category("Columns"), Description("CHAR")> _
        Public Property idCust() As Integer
            Get
                Return _idCust
            End Get
            Set(ByVal value As Integer)
                _idCust = value
            End Set
        End Property

        Dim _Artic As String
        <Category("Columns"), Description("CHAR")> _
        Public Property Artic() As String
            Get
                Return _Artic
            End Get
            Set(ByVal value As String)
                _Artic = value
            End Set
        End Property
        'etc...'
    End Class 'Order'
End Class 'Tables'

嗯,我可以使用接口,但我宁愿只使用一个抽象基类,而不是在每个类中重新定义它。这样我就可以测试基类代码,并将其放在一个集中的位置。虽然我可以使用接口和抽象基类的组合来解决这个问题。我可以使用接口,但我宁愿只使用一个抽象基类,而不是在每个类中重新定义它。这样我就可以测试基类代码,并将其放在一个集中的位置。尽管我可能会使用接口和抽象基类的组合来解决它。所有这些Vb代码的较短版本所有这些Vb代码的较短版本