In our current project I am using a generic interface iService which is inherited by all other service interfaces. For instance IService is inherited by ILogService.
The ILogService interface is then implemented by LogService as below:
Public Interface IService(Of T)
Sub Save(ByVal T As IEntity)
Sub Remove(ByVal T As IEntity)
Function FindBy(ByVal Id As Guid) As T
Function FindAll() As IEnumerable(Of T)
End Interface
Public Interface ILogService
Inherits IService(Of Log)
Function FindLogsByOwner(ByVal Owner As Guid, ByVal visibility As LogVisibility) As IList(Of Log)
Function FindAllLogsByVisibility(ByVal visibility As LogVisibility) As IList(Of Log)
Function FindAllLogsByType(ByVal type As LogType) As IList(Of Log)
End Interface
Public Class LogService
Implements ILogService
Public Function FindAll() As System.Collections.Generic.IEnumerable(Of Model.CSLS.Log) Implements Infrastructure.Domain.IService(Of Model.CSLS.Log).FindAll
End Function
Public Function FindBy(Id As System.Guid) As Model.CSLS.Log Implements Infrastructure.Domain.IService(Of Model.CSLS.Log).FindBy
End Function
Public Sub Remove(T As Infrastructure.Domain.IEntity) Implements Infrastructure.Domain.IService(Of Model.CSLS.Log).Remove
End Sub
Public Sub Save(T As Infrastructure.Domain.IEntity) Implements Infrastructure.Domain.IService(Of Model.CSLS.Log).Save
End Sub
Public Function FindAllLogsByType(type As Model.CSLS.LogType) As System.Collections.Generic.IList(Of Model.CSLS.Log) Implements Model.CSLS.ILogService.FindAllLogsByType
End Function
Public Function FindAllLogsByVisibility(visibility As Model.CSLS.LogVisibility) As System.Collections.Generic.IList(Of Model.CSLS.Log) Implements Model.CSLS.ILogService.FindAllLogsByVisibility
End Function
Public Function FindLogsByOwner(Owner As System.Guid, visibility As Model.CSLS.LogVisibility) As System.Collections.Generic.IList(Of Model.CSLS.Log) Implements Model.CSLS.ILogService.FindLogsByOwner
End Function
End Class
Help Needed: I am trying to understand that when I am implementing ILogService interface I still get the functions/subs in the LogService class containing:
method parameter T of Type IEntity instead of Log
How can I update the method signature so T is displayed as Log?
What am I doing wrong?
Are you talking about these?
Sub Save(ByVal T As IEntity)
Sub Remove(ByVal T As IEntity)
This is very confusing, because in the above methods T is the name of a method parameter, not a generic type parameter. It could just as easily have been foo or bar. In each case the type of T is IEntity.
If the intention here was that Save and Remove should each accept an argument of type T, but that type T must implement IEntity, this is how you would express that:
Public Interface IService(Of T As IEntity)
Sub Save(ByVal entity As T)
Sub Remove(ByVal entity As T)
Function FindBy(ByVal Id As Guid) As T
Function FindAll() As IEnumerable(Of T)
End Interface
#DanTao is correct if that is the intention. If, however, you just intended the name of the method parameter to be specified by the generic type, that is not possible.
However, you can specify any name you like in the implementing method, so you can use Log if you want, but you can't enforce it (and some FxCop rule will warn you haven't used the same parameter name as specified in the interface).
Related
I'm already searching for hours, but I cannot find any solution or even a possible way, that fits.
I need a way to enforce, that multiple classes have a shared member. This classes can not be inherits another class, because they are entity data model classes and i work on a partial class file beside the autogenerated files.
I tried to use an interface, but interfaces does not provide the option to declare a member as shared.
My try was like:
Public Interface IInterfaceA
ReadOnly Property PropA as String
End Interface
Public Partial Class ClassA
Implements IInterfaceA
Public Shared ReadOnly Property SPropA As String
Get
Return "FixedValueStringForClassA"
End Get
End Property
Public ReadOnly Property PropA As String Implements IInterfaceA.PropA
Get
Return SPropA
End Get
End Property
End Class
Public Partial Class ClassB
Implements IInterfaceA
Public Shared ReadOnly Property SPropA As String
Get
Return "FixedValueStringForClassB"
End Get
End Property
Public ReadOnly Property PropA As String Implements IInterfaceA.PropA
Get
Return SPropA
End Get
End Property
End Class
So I can call the PropA Member, when I get e.g. an array of types, that implements IInterfaceA.
But my first implementation does not enforce the shared property, only the normal property. To call the normal property, I would need an instance of that type, but this is not the way I searching for.
Maybe there is another solution to this problem.
Unfortunately you can't force a class to implement a shared member.
However, you CAN share extension methods from a module.
I had a similar problem recently with needing to share functions with multiple classes but still be able to run them as that class. Which I solved using extension methods.
Basically how it works is the module extends all objects that implement an interface, which can be conveniently included with the module, that interface will include anything the module will need access to from the calling class and the module will include anything that needs to be shared between all classes
Public Module SharedProp
Dim PropA As String
<Extension()>
Public Function GetPropA(Of T As IInterfaceA)(this As T) As String
Return PropA
End Function
<Extension()>
Public Sub SetPropA(Of T As IInterfaceA)(this As T, value As String)
PropA = value
End Function
Public Interface IInterfaceA
Property PropA As String
End Interface
End Module
so long as the module is included, any class which impliments your interface will have access to the module's extension methods, which in turn has access to the module's implicitly shared members
Imports SharedProp
Public Partial Class ClassA
Implements IInterfaceA
Public Property PropA As String Implements IInterfaceA.PropA
Get
Return Me.GetPropA()
End Get
Set(value As String)
Me.SetPropA(value)
End Set
End Property
End Class
Public Partial Class ClassB
Implements IInterfaceA
Public Property PropA As String Implements IInterfaceA.PropA
Get
Return Me.GetPropA()
End Get
Set(value As String)
Me.SetPropA(value)
End Set
End Property
End Class
Hope that helps solve your problem!
EDIT: Shared on Class basis instead of Interface
Public Module SharedProp
Dim PropA As Dictionary(Of Type, String)
<Extension()>
Public Function GetPropA(Of T As IInterfaceA)(this As T) As String
If PropA.ContainsKey(GetType(T)) Then
Return PropA(T)
Else
Return Nothing
End Function
<Extension()>
Public Sub SetPropA(Of T As IInterfaceA)(this As T, value As String) As String
If PropA.ContainsKey(GetType(T) Then
PropA(T) = value
Else
PropA.Add(GetType(T), value)
End If
End Function
Public Interface IInterfaceA
Property PropA As String
End Interface
End Module
I will try to simplify as possible. In my solution i got 3 separated projects:
Main - where i use Bal
Bal - business logic, eg. classes:
Artikel
Material
Dal - data layer logic, eg. classes:
DALArtikel
DALMaterial
Now Dal's classes implements interface IDAL which looks like follows:
Public Interface IDAL
Function isExist(name As String) As Boolean
Function GetIdByName(name As String) As Integer
Function GetNameById(pId As Integer) As String
End Interface
Then i can call interface's methods from Bal's project. Every BAL's class has it's DAL class like for Artikel is DALArtikel.
Now every BAL's classes inherits from one Base class which looks like below. This Base class implements interface similar to mentioned above called IGetInformation
Public Class Base
Implements IGetInformation
Property Id As Integer
Property DAL As DataLayer.IDAL
Protected Sub New()
End Sub
Protected Sub New(dal As DataLayer.IDAL)
Me.DAL = dal
End Sub
Protected Sub New(pId As Integer)
_Id = pId
End Sub
Public Overridable Function IsExist(name As String) As Boolean Implements IGetInformation.IsExist
Return DAL.isExist(name)
End Function
Public Overridable Function GetNameById(pId As Integer) As String Implements IGetInformation.GetNameById
Return DAL.GetNameById(pId)
End Function
Public Overridable Function GetIdByName(pName As String) As Integer Implements IGetInformation.GetIdByName
Return DAL.GetIdByName(pName)
End Function
Mentioned interface:
Public Interface IGetInformation
Function isExist(name As String) As Boolean
Function GetIdByName(name As String) As Integer
Function GetNameById(pId As Integer) As String
End Interface
So every Bal's class like Artikel is constructed as following:
Public Class Artikel
Inherits Base
Property Serie As String
Property Nummer As String
Property Name As String
Sub New()
MyBase.New(New DALArtikel)
End Sub
Sub New(pId As Integer)
MyBase.New(New DALArtikel)
Id = pId
End Sub
Sub New(pId As Integer, pSerie As String)
MyBase.New(New DALArtikel)
Id = pId
Serie = pSerie
End Sub
This way i can instatiate artikel class in Main project and call it's e.g isExist method without specyfing specific DAL class associated with it as in Artikel class constructor it was already specified. The problem is now when i want to add new method which will be not in IDAL interface i have to implement like this in Artikel:
Public Function IsExistBarcode(barcode As String) As Boolean
Return New DataLayer.DALArtikel().CheckIfBarcodeExist(barcode)
End Function
so this time i have to specify DALArtikel before i call CheckIfBarcodeExist as my property DAL doesn't know it.
Generally i don't like the way as it is currently, you see that i use two separate exactly the same content interfaces for bal's and dal's projects and the logic behind. Do you know other efficient way which i could change current logic to be let's say 'better'?
Appreciate possible improvment example according to my situation. Sorry for long post but couldn't make it more less. If something unclear let me know.
I will try to explain the problem as clearly as possible. I am not sure if what I need is possible but expect that there must be some solution to this. I wont be able to put in actual code here but will add whatever is needed to explain the problem.
Initially we had two separate classes as defined below.
Imports QMember48
Public Class Member48
Public Function ProcessInfo(reqctx as Member48.RequestContext, memid as String)
'Code here
End Function
Public Function UpdateInfo(partner as Member48.Partner, memid as String)
'Code here
End Function
'Other methods and functions come here
End Class
Imports QMember50
Public Class Member50
Public Function ProcessInfo(reqctx as Member50.RequestContext, memid as String)
'Code here
End Function
Public Function UpdateInfo(partner as Member50.Partner, memid as String)
'Code here
End Function
'Other methods and functions come here
End Class
Basically these two classes have common methods and functions but the references are different.
We next decided to create a factory pattern to get the objects of these classes based on some input parameter.
Our current implementation of code is like this:
'Base class definition
Imports QMember48
Public MustInherit Class Member
Public MustOverride Function ProcessInfo(reqctx as Member48.RequestContext, memid as String)
Public MustOverride Function UpdateInfo(partner as Member48.Partner, memid as String)
End Class
'Factory
Public Module MemFactory
Function GetMember(val as string) as Member
'Do some processing here
If val = "500" return new Member50() else return new Member48()
End Function
End Module
The problem is that the base class refers to Member48 and when the factory generates an object for Member50, the reference to Member48 still remains. This needs to be corrected somehow in the base class. If an object of Member50 is needed, there should not be any reference to Member48. But again how do we define the base class without any hardcoded import of Member48/50 ?
Is there any way to resolve this issue? If more details are needed, I can add later.
Thanks.
The problem is that both Members don't have any method in common. There may be two methods with the same name, but those methods have different signatures. You can neither pass a Member48.RequestContext to a Member50, nor can you pass a Member50.RequestContext to a Member48. That's why inheritance can't applied here reasonably. A common base class of both members would be empty.
You could use a generic base class as follows:
MustInherit Class Member(Of TRequest, TPartner)
Public MustOverride Function ProcessInfo(reqctx As TRequest, memid As String)
Public MustOverride Function UpdateInfo(partner As TPartner, memid As String)
End Class
Class Member48
Inherits Member(Of QMember48.RequestContext, QMember48.Partner)
'...
End Class
Class Member50
Inherits Member(Of QMember50.RequestContext, QMember50.Partner)
'...
End Class
However, this base class does not give you any advantage with a factory. The factory would have to return an untyped Member and you'll lose any advantage of the generic implementation.
Another approach is trying to unify the RequestContexts and Partners. If the members only rely on common members, this can be done very easily with an interface. If there are no common members, you could even use an empty interface (as a hint of the requested type) and do the following:
MustInherit Class Member
Public MustOverride Function ProcessInfo(reqctx As IRequestContext, memid As String)
'...
End Class
The concrete Member would be responsible for checking for the correct type and could throw an exception if the wrong type is being passed.
The last approach is to go without any base class and let the factory return an Object (or maybe an empty base class). This might be the cleanest solution because it does not introduce any artificial inheritance where there is none. Of course, you would have to do type checks each time you access the object, but that is the same with most other methods.
Finally, there is not really a nice solution for your problem. Maybe you could revise your architecture and see if there are smarter structures or if you really need the Members as listed above.
Create a baseclass or interface for RequestContext and Partner, and let Member48.RequestContext/Member50.RequestContext and Member48.Partner/Member50.Partner implement those interfaces:
Public Interface IRequestContext
End Interface
Public Interface IPartner
End Interface
Class Member48RequestContext
Implements IRequestContext
End Class
Class Member48Partner
Implements IPartner
End Class
Class Member50RequestContext
Implements IRequestContext
End Class
Class Member50Partner
Implements IPartner
End Class
Now you can create a base class that accepts an IRequestContest and an IPartner:
Public MustInherit Class Member
Public MustOverride Function ProcessInfo(reqctx as IRequestContext, memid as String)
Public MustOverride Function UpdateInfo(partner as IPartner, memid as String)
End Class
and the implementation of your concrete member classes look like
Public Class Member50
Inherits Member
Public Overrides Function ProcessInfo(reqctx as IRequestContext, memid as String)
End Function
Public Overrides Function UpdateInfo(partner as IPartner, memid as String)
End Function
End Class
If you want, you could also create another subclass using generics:
Public MustInherit Class Member(Of TRequest As IRequestContext, TPartner As IPartner)
Inherits Member
Public Overrides Function ProcessInfo(reqctx as IRequestContext, memid as String)
Return ProcessInfo(DirectCast(reqctx, TRequest), memid)
End Function
Public Overrides Function UpdateInfo(partner as IPartner, memid as String)
Return UpdateInfo(DirectCast(partner, TPartner), memid)
End Function
Public Overloads MustOverride Function ProcessInfo(reqctx as TRequest, memid as String)
Public Overloads MustOverride Function UpdateInfo(partner as TPartner, memid as String)
End Class
and an implementation:
Public Class Member48
Inherits Member(Of Member48RequestContext, Member48Partner)
Public Overrides Function ProcessInfo(reqctx as Member48RequestContext, memid as String)
End Function
Public Overrides Function UpdateInfo(partner as Member48Partner, memid as String)
End Function
End Class
Note how Member48 only accepts an Member48RequestContext , instead of any IRequestContext like Member50. It's up to you if you want this extra safety.
Your factory method stays the same:
Function GetMember(val as string) as Member
'Do some processing here
If val = "500" Then
Return New Member50()
Else
Return New Member48()
End If
End Function
However, your factory still needs a reference to both Member50 and Member48, since it creates the concrete classes.
Another approach is to use a DI-container like StructureMap, which is able to scan all your assemblies automatically for all types that implement Member(Of TRequest As IRequestContext, TPartner As IPartner), asign a key to each one, and return the correct instance ,e.g. Member50 if asked for a specifig key, e.g. 500. But a full blown example of such a configuration would be out of scope of this question/answer.
Trying to get my head around generic interfaces and classes. How do I 'get T' when using my class in the new method and call data.method using this type?
Public MustInherit Class RepositoryBase(Of T)
Implements IRepository(Of T)
Private Data As IDAL
Public Sub New()
Data = DTOParserFactory.GetParser(T.GetType().ToString())
End Sub
Public Sub delete(BaseDTO As T) Implements Domain.Business.IRepository(Of T).delete
'Data.delete(Convert.ChangeType(BaseDTO, TypeOf(Type))
End Sub
Public Function getAll() As System.Linq.IQueryable(Of T) Implements Domain.Business.IRepository(Of T).getAll
'Return Data.getAll()()
End Function
End Class
I'm assuming you need to get the Type object for T?
In your constructor
Public Sub New()
Data = DTOParserFactory.GetParser(GetType(T).ToString())
End Sub
I'm not super clear on the question, but perhaps this is what you are looking for.
Assuming you have a common base class BaseDTO then you would define your RepositoryBase class like this:
Public MustInherit Class RepositoryBase(Of T As BaseDTO)
Then you declare an instace of the class like this:
Dim userRepository As New RepositoryBase(Of User)()
What this does is constrain T to be a subclass of BaseDTO, and gives you access to all of BaseDTO's methods.
Ok... So I have created my model using EF4. Great!
I then turned off the code generation and downloaded this extension: http://visualstudiogallery.msdn.microsoft.com/23df0450-5677-4926-96cc-173d02752313
(POCO Entity Generator). Awesome!
Ran it, and it generates all of my classes. Is that all I have to do? It seems to work, my repositories get to the objects and persist to the DB.
Please have a look at the following code and let me know if I am on the right track.
** Sample Code **
Controller:
Namespace Controllers
Public Class HomeController
Inherits System.Web.Mvc.Controller
Function Index() As ActionResult
Return View(New Models.HomeModel)
End Function
End Class
End Namespace
Model:
Namespace Models
Public Class HomeModel
Private _Repository As Titan.Business.Repositories.ICustomerRepository
Private _SalesRepRepo As Titan.Business.Repositories.ISalesRepresentativeRepository
Public Property Customers As IEnumerable(Of Titan.Business.Customer)
Public Property SalesReps As IEnumerable(Of Titan.Business.SalesRepresentative)
Public Sub New()
_Repository = New Titan.Business.Repositories.CustomerRepository
_SalesRepRepo = New Titan.Business.Repositories.SalesRepresentativeRepository
_Customers = _Repository.Query(Function(x) x.LastName.StartsWith("Str"))
_SalesReps = _SalesRepRepo.Query(Function(x) x.LastName.StartsWith("Str"))
End Sub
End Class
End Namespace
Repository and Interfaces:
Namespace Repositories
Public Interface IRepository(Of T)
Function Query(ByVal Predicate As System.Linq.Expressions.Expression(Of Func(Of T, Boolean))) As IEnumerable(Of T)
Function GetByID(ByVal ID As Integer) As T
Sub Add(ByVal Entity As T)
Sub Delete(ByVal Entity As T)
Sub Save(ByVal Entity As T)
End Interface
Public Interface ICustomerRepository
Inherits IRepository(Of Customer)
End Interface
Public Interface ISalesRepresentativeRepository
Inherits IRepository(Of SalesRepresentative)
End Interface
End Namespace
Namespace Repositories
Public Class SalesRepresentativeRepository
Implements ISalesRepresentativeRepository
Public Sub Add(ByVal Entity As SalesRepresentative) Implements IRepository(Of SalesRepresentative).Add
End Sub
Public Sub Delete(ByVal Entity As SalesRepresentative) Implements IRepository(Of SalesRepresentative).Delete
End Sub
Public Function GetByID(ByVal ID As Integer) As SalesRepresentative Implements IRepository(Of SalesRepresentative).GetByID
End Function
Public Function Query(ByVal Predicate As System.Linq.Expressions.Expression(Of System.Func(Of SalesRepresentative, Boolean))) As System.Collections.Generic.IEnumerable(Of SalesRepresentative) Implements IRepository(Of SalesRepresentative).Query
Using db As New GTGContainer
Return db.SalesRepresentatives.Where(Predicate).ToList
End Using
End Function
Public Sub Save(ByVal Entity As SalesRepresentative) Implements IRepository(Of SalesRepresentative).Save
End Sub
End Class
End Namespace
Any suggestions would be so helpful to me.
Where does the service layer fit in?
What about the AutoMapper? Do I even need to use that now?
Dependency Injection? Anyone care to explain.
Thanks a bunch,
Sam
There's a great article by Scott Allen about Testing Entity Framework 4 - creating the POCO classes is a good first step, but if you want to test you business layer separate from EF you will have to introduce a Unit of Work that coordinates saving state across multiple repositories and allows DI.