Is this possible in object-oriented design? I'd like to specify that in an inheritance tree, the type of a property in the child classes is different from the type of that property in the parent class. But the types are polymorphic because they derive from
the type used in the parent class. e.g.:
<pre class="prettyprint"><br /><br />Public MustInherit Class DAO
Public MustOverride ReadOnly Property connectionString As String
Protected MustOverride Property conn As DbConnection
End Class
Public Class DAOMSSQL
Inherits DAO
Public Overrides ReadOnly Property connectionString As String
Protected Overrides Property conn As SqlConnection
End Class
Public Class DAOMySQL
Inherits DAO
Public Overrides ReadOnly Property connectionString As String
Protected Overrides Property conn As OdbcConnection
End Class</pre>
Both OdbcConnection and SqlConnection inherit from DbConnection. This gives a compile error. Another approach is needed, anyone know how?
1. Use DbConnection as the type for the 'conn' property (of the DAO class) and don't override it in the derived classes. The problem with this solution is that the type of the property doesn't fully reflect the type of the object it represents (ie it isn't
stongly typed).
2. Convert the DAO class into a generic class, which takes the type of the connection as a generic parameter. The benefit of this is that the property is strongly type.
The C# equivalent (sorry I don't know VB) is:
public abstract class DAO<TConnection>
where TConnection : DbConnection
{
...
public TConnection Connection { get; set; }
}
public class DAOMSSQL : DAO<SqlConnection> {}
public class DAOMySQL: DAO<MySqlConnection> {}
Hi steven, thanks for your answer. I did this and started doing it also for other properties, method return types an argument types used in the original Class, that is now being converted to DAO:
Public MustInherit Class DAO(Of TConnection As DbConnection, TCommand As DbCommand, TDataAdapter As DbDataAdapter, TDataReader As DbDataReader)
Public MustOverride ReadOnly Property connectionString As String
Public Property Connection() As TConnection
...
End Property
Private m_Connection As TConnection
Protected MustOverride Function GetDataReader(ByVal SQLCommandString As String) As TDataReader
Protected MustOverride Function GetDataAdapter(ByVal SQLCommandString As String) As TDataAdapter
Protected MustOverride Function GetDataAdapter(ByVal T As TCommand) As TDataAdapter
In the child classes (DAOMSSQL, DAOMySQL) these 3 last methods are implemented:
Public Class DAOMSSQL
Inherits DAO(Of SqlConnection, SqlDataAdapter, SqlDataReader)
Public Overrides ReadOnly Property connectionString As String
Get
Return ConfigurationManager.AppSettings("SQLConnectionString")
End Get
End Property
Protected Overrides Function GetDataReader(ByVal OdbcCommandString As String) As OdbcDataReader
'If Not conn Is Nothing Then
Dim SDR As OdbcDataReader
Dim myOdbcCommand As OdbcCommand = New OdbcCommand(OdbcCommandString, Connection())
SDR = myOdbcCommand.ExecuteReader()
Return SDR
'End If
End Function
Protected Overrides Function GetDataAdapter(ByVal OdbcCommandString As String) As OdbcDataAdapter
' If Not conn Is Nothing Then
Dim SDA As New OdbcDataAdapter
Dim myOdbcCommand As OdbcCommand = New OdbcCommand(OdbcCommandString, Connection())
SDA.SelectCommand = myOdbcCommand
Return SDA
' End If
End Function
Protected Overrides Function GetDataAdapter(ByVal myOdbcCommand As OdbcCommand) As OdbcDataAdapter
Dim SDA As New OdbcDataAdapter
SDA.SelectCommand = myOdbcCommand
Return SDA
End Function
End Class
However, I guess this is code duplication as SqlCommand can be genericized to DbCommand in the parent class. I guess the Odbc and Sql namespaces are totally symmetric in the classes they have, so I can have the method bodies doing the same stuff but with different types?
I want to keep my parent methods MustOverride (abstract), so that any child class is forced to implement these methods. However, considering the use of generics, I'd need to keep the implementation inside the parent DAO methods and not in the child MSSQL methods, which is contrary to abstract methods. Can I combine generics with methods that need to be enforced in base classes?
Further methods that need to be refactored by this are eg.:
Public Function GetDataTable(ByVal myDataTable As DataTable, ByVal SQLCommandString As String) As DataTable
Using conn As New SqlConnection(connectionString)
conn.Open()
Dim SDA As SqlDataAdapter
Dim mySQLCommand As SqlCommand = New SqlCommand(SQLCommandString, conn)
SDA = GetDataAdapter(mySQLCommand)
SDA.Fill(myDataTable)
conn.Close()
Return myDataTable
End Using
End Function
I'm not sure why you feel you need to enforce the implementation in derived classes. The point of generics (or at least one of the points) is that you can implement base definitions but know that it's strongly typed. For example:
protected TDataReader GetDataReader(string commandString)
{
var command = Connection.CreateCommand();
command.CommandText = commandString;
return command.ExecuteReader() as TDataReader;
}
I thought it was needed to have the derived classes call MyBase.MethodName(), but yeah, they <i>are</i> the supertype. With generics I can rest assured that all the types are respected?
Implementing it in a derived class would only make sense if the method had to do slightly different stuff?
Ok, so now I got my two classes thet derive from a generic class. But how do I instantiate them? http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx gives an incredibly convoluted method with MakeGenericType(), but how do I do it a easy way, in a simple
factory?
Public MustInherit Class DAO(Of TConnection As {DbConnection, New}, TCommand As {DbCommand, New}, TDataAdapter As {DbDataAdapter, New}, TDataReader As DbDataReader)
End Class
Public Class DAOMSSQL
Inherits DAO(Of SqlConnection, SqlCommand, SqlDataAdapter, SqlDataReader)
Public Overrides ReadOnly Property connectionString As String
Get
Return ConfigurationManager.AppSettings("SQLConnectionString")
End Get
End Property
End Class
With easy, I mean something like this:
Public Class DAOFactory
Private _DAO As DAO(Of DbConnection, DbCommand, DbDataAdapter, DbDataReader)
Private _myType As String
Public Sub New(ByVal myType As String)
_myType = myType
End Sub
Public Function GetDAO() As DAO
If _myType = "MySQL" Then
_DAO = New DAOMySQL(Of OdbcConnection, OdbcCommand, OdbcDataAdapter, OdbcDataReader)
ElseIf _myType = "MSSQL" Then
End If
Return _DAO
End Function
This gives an error on line 3 'Type argument 'System.Data.Common.DbConnection' must have a public parameterless instance constructor to satisfy the 'New' constraint for type parameter 'TConnection'. How do I get the new() constraint into the constructor?
It also gives an error on line 12: 'Site.DAOMySQL' has no type parameters and so cannot have type arguments.'
<pre class="prettyprint"><br /><br />Public MustInherit Class DAO
Public MustOverride ReadOnly Property connectionString As String
Protected MustOverride Property conn As DbConnection
End Class
Public Class DAOMSSQL
Inherits DAO
Public Overrides ReadOnly Property connectionString As String
Protected Overrides Property conn As SqlConnection
End Class
Public Class DAOMySQL
Inherits DAO
Public Overrides ReadOnly Property connectionString As String
Protected Overrides Property conn As OdbcConnection
End Class</pre>
Both OdbcConnection and SqlConnection inherit from DbConnection. This gives a compile error. Another approach is needed, anyone know how?
Hi,
Based on my experience, you can address your requirement by using the Generics rather than inheritance, please try this:
Namespace ConsoleAplication1
Class Program
Private Shared Sub Main(args As String())
Dim dao As New DAO(Of String, SqlConnection)()
Dim con As New SqlConnection("yourConnectionString")
dao.conn=con
End Sub
Public Class DAO(Of T, S)
Public ReadOnly Property connectionString() As T
Public Property conn() As S
Get
End Get
Set
End set
End Property
End Class
End Namespace
Please mark the replies as answers if they help or unmark if not.
Feedback to us
vthomas
Member
44 Points
37 Posts
Inheritance of abstract method and Generics with Odbc... and Sql... types
May 26, 2011 01:14 PM|LINK
Is this possible in object-oriented design? I'd like to specify that in an inheritance tree, the type of a property in the child classes is different from the type of that property in the parent class. But the types are polymorphic because they derive from the type used in the parent class. e.g.:
<pre class="prettyprint"><br /><br />Public MustInherit Class DAO Public MustOverride ReadOnly Property connectionString As String Protected MustOverride Property conn As DbConnection End Class Public Class DAOMSSQL Inherits DAO Public Overrides ReadOnly Property connectionString As String Protected Overrides Property conn As SqlConnection End Class Public Class DAOMySQL Inherits DAO Public Overrides ReadOnly Property connectionString As String Protected Overrides Property conn As OdbcConnection End Class</pre> Both OdbcConnection and SqlConnection inherit from DbConnection. This gives a compile error. Another approach is needed, anyone know how?stevenbey
All-Star
16526 Points
3378 Posts
Re: Inheritance of abstract method and Generics with Odbc... and Sql... types
May 26, 2011 03:16 PM|LINK
There are two ways to solve this:
1. Use DbConnection as the type for the 'conn' property (of the DAO class) and don't override it in the derived classes. The problem with this solution is that the type of the property doesn't fully reflect the type of the object it represents (ie it isn't stongly typed).
2. Convert the DAO class into a generic class, which takes the type of the connection as a generic parameter. The benefit of this is that the property is strongly type.
The C# equivalent (sorry I don't know VB) is:
public abstract class DAO<TConnection> where TConnection : DbConnection { ... public TConnection Connection { get; set; } } public class DAOMSSQL : DAO<SqlConnection> {} public class DAOMySQL: DAO<MySqlConnection> {}http://stevenbey.com
Recursion: see Recursion
vthomas
Member
44 Points
37 Posts
Re: Inheritance of abstract method and Generics with Odbc... and Sql... types
May 27, 2011 12:38 PM|LINK
Hi steven, thanks for your answer. I did this and started doing it also for other properties, method return types an argument types used in the original Class, that is now being converted to DAO:
Public MustInherit Class DAO(Of TConnection As DbConnection, TCommand As DbCommand, TDataAdapter As DbDataAdapter, TDataReader As DbDataReader) Public MustOverride ReadOnly Property connectionString As String Public Property Connection() As TConnection ... End Property Private m_Connection As TConnection Protected MustOverride Function GetDataReader(ByVal SQLCommandString As String) As TDataReader Protected MustOverride Function GetDataAdapter(ByVal SQLCommandString As String) As TDataAdapter Protected MustOverride Function GetDataAdapter(ByVal T As TCommand) As TDataAdapterIn the child classes (DAOMSSQL, DAOMySQL) these 3 last methods are implemented:
Public Class DAOMSSQL Inherits DAO(Of SqlConnection, SqlDataAdapter, SqlDataReader) Public Overrides ReadOnly Property connectionString As String Get Return ConfigurationManager.AppSettings("SQLConnectionString") End Get End Property Protected Overrides Function GetDataReader(ByVal OdbcCommandString As String) As OdbcDataReader 'If Not conn Is Nothing Then Dim SDR As OdbcDataReader Dim myOdbcCommand As OdbcCommand = New OdbcCommand(OdbcCommandString, Connection()) SDR = myOdbcCommand.ExecuteReader() Return SDR 'End If End Function Protected Overrides Function GetDataAdapter(ByVal OdbcCommandString As String) As OdbcDataAdapter ' If Not conn Is Nothing Then Dim SDA As New OdbcDataAdapter Dim myOdbcCommand As OdbcCommand = New OdbcCommand(OdbcCommandString, Connection()) SDA.SelectCommand = myOdbcCommand Return SDA ' End If End Function Protected Overrides Function GetDataAdapter(ByVal myOdbcCommand As OdbcCommand) As OdbcDataAdapter Dim SDA As New OdbcDataAdapter SDA.SelectCommand = myOdbcCommand Return SDA End Function End ClassHowever, I guess this is code duplication as SqlCommand can be genericized to DbCommand in the parent class. I guess the Odbc and Sql namespaces are totally symmetric in the classes they have, so I can have the method bodies doing the same stuff but with different types?
I want to keep my parent methods MustOverride (abstract), so that any child class is forced to implement these methods. However, considering the use of generics, I'd need to keep the implementation inside the parent DAO methods and not in the child MSSQL methods, which is contrary to abstract methods. Can I combine generics with methods that need to be enforced in base classes?
Further methods that need to be refactored by this are eg.:
Public Function GetDataTable(ByVal myDataTable As DataTable, ByVal SQLCommandString As String) As DataTable Using conn As New SqlConnection(connectionString) conn.Open() Dim SDA As SqlDataAdapter Dim mySQLCommand As SqlCommand = New SqlCommand(SQLCommandString, conn) SDA = GetDataAdapter(mySQLCommand) SDA.Fill(myDataTable) conn.Close() Return myDataTable End Using End Functionstevenbey
All-Star
16526 Points
3378 Posts
Re: Inheritance of abstract method and Generics with Odbc... and Sql... types
May 27, 2011 02:32 PM|LINK
I'm not sure why you feel you need to enforce the implementation in derived classes. The point of generics (or at least one of the points) is that you can implement base definitions but know that it's strongly typed. For example:
protected TDataReader GetDataReader(string commandString) { var command = Connection.CreateCommand(); command.CommandText = commandString; return command.ExecuteReader() as TDataReader; }http://stevenbey.com
Recursion: see Recursion
vthomas
Member
44 Points
37 Posts
Re: Inheritance of abstract method and Generics with Odbc... and Sql... types
May 27, 2011 03:03 PM|LINK
Thanks for your answer.
I thought it was needed to have the derived classes call MyBase.MethodName(), but yeah, they <i>are</i> the supertype. With generics I can rest assured that all the types are respected?
Implementing it in a derived class would only make sense if the method had to do slightly different stuff?
stevenbey
All-Star
16526 Points
3378 Posts
Re: Inheritance of abstract method and Generics with Odbc... and Sql... types
May 27, 2011 03:28 PM|LINK
Exactly, in which case you would declare the method virtual (or the VB equivalent).
http://stevenbey.com
Recursion: see Recursion
vthomas
Member
44 Points
37 Posts
Re: Inheritance of abstract method and Generics with Odbc... and Sql... types
May 30, 2011 08:36 AM|LINK
Ok, so now I got my two classes thet derive from a generic class. But how do I instantiate them? http://msdn.microsoft.com/en-us/library/b8ytshk6.aspx gives an incredibly convoluted method with MakeGenericType(), but how do I do it a easy way, in a simple factory?
Public MustInherit Class DAO(Of TConnection As {DbConnection, New}, TCommand As {DbCommand, New}, TDataAdapter As {DbDataAdapter, New}, TDataReader As DbDataReader) End Class Public Class DAOMSSQL Inherits DAO(Of SqlConnection, SqlCommand, SqlDataAdapter, SqlDataReader) Public Overrides ReadOnly Property connectionString As String Get Return ConfigurationManager.AppSettings("SQLConnectionString") End Get End Property End ClassWith easy, I mean something like this:
Public Class DAOFactory Private _DAO As DAO(Of DbConnection, DbCommand, DbDataAdapter, DbDataReader) Private _myType As String Public Sub New(ByVal myType As String) _myType = myType End Sub Public Function GetDAO() As DAO If _myType = "MySQL" Then _DAO = New DAOMySQL(Of OdbcConnection, OdbcCommand, OdbcDataAdapter, OdbcDataReader) ElseIf _myType = "MSSQL" Then End If Return _DAO End FunctionThis gives an error on line 3 'Type argument 'System.Data.Common.DbConnection' must have a public parameterless instance constructor to satisfy the 'New' constraint for type parameter 'TConnection'. How do I get the new() constraint into the constructor? It also gives an error on line 12: 'Site.DAOMySQL' has no type parameters and so cannot have type arguments.'
vthomas
Member
44 Points
37 Posts
Re: Inheritance of abstract method and Generics with Odbc... and Sql... types
May 30, 2011 10:15 AM|LINK
What is the contructor for DAOMSSQL, that has several class-level constraints and constructor constraints?
Mamba Dai - ...
All-Star
23531 Points
2683 Posts
Microsoft
Re: Inheritance of abstract method and Generics with Odbc... and Sql... types
Jun 02, 2011 03:42 AM|LINK
Hi,
Based on my experience, you can address your requirement by using the Generics rather than inheritance, please try this:
Namespace ConsoleAplication1 Class Program Private Shared Sub Main(args As String()) Dim dao As New DAO(Of String, SqlConnection)() Dim con As New SqlConnection("yourConnectionString") dao.conn=con End Sub Public Class DAO(Of T, S) Public ReadOnly Property connectionString() As T Public Property conn() As S Get End Get Set End set End Property End Class End NamespaceFeedback to us
Develop and promote your apps in Windows Store