I'm using a factory to select from several services that are implementing the same generic interface. I have the factory written like this:
Public Class JurisdictionServiceFactory
Private JurisdictionTypeMapper As Dictionary(Of String, Object)
Sub New()
JurisdictionTypeMapper = New Dictionary(Of String, Object)
JurisdictionTypeMapper.Add("CountryJurisdiction", ProjectGlobals.UnityContainer.Resolve(Of IJurisdictionService(Of CountryJurisdiction)))
JurisdictionTypeMapper.Add("StateJurisdiction", ProjectGlobals.UnityContainer.Resolve(Of IJurisdictionService(Of StateJurisdiction)))
JurisdictionTypeMapper.Add("CountyJurisdiction", ProjectGlobals.UnityContainer.Resolve(Of IJurisdictionService(Of CountyJurisdiction)))
JurisdictionTypeMapper.Add("CityJurisdiction", ProjectGlobals.UnityContainer.Resolve(Of IJurisdictionService(Of CityJurisdiction)))
JurisdictionTypeMapper.Add("OtherJurisdiction", ProjectGlobals.UnityContainer.Resolve(Of IJurisdictionService(Of OtherJurisdiction)))
End Sub
Public Function getJurisdictionService(type As String) As Object
Return JurisdictionTypeMapper(type)
End Function
End Class
I would like to replace 'Object' as the value type with something that would allow the compiler to know what methods exist on the object. For example, I want to be able to use autocomplete. I've tried doing this: Private JurisdictionTypeMapper As Dictionary(Of String, IJurisdictionService(Of ))
, but I just get a message: "Type expected".
This is IJurisdictionService:
Public Interface IJurisdictionService(Of t)
Inherits IDisposable
Function GetJurisdictionsByCompany(companyId As Integer) As List(Of t)
Sub AddJurisdiction(jurisdiction As t)
End Interface
This is an example implementation:
Public Class CountryJurisdictionService
Implements IJurisdictionService(Of CountryJurisdiction)
Private jurisdictionRepository As IRepository(Of CountryJurisdiction)
Public Sub New(jurisdictionRepository As IRepository(Of CountryJurisdiction))
Me.jurisdictionRepository = jurisdictionRepository
End Sub
Public Sub AddJurisdiction(jurisdiction As CountryJurisdiction) Implements IJurisdictionService(Of CountryJurisdiction).AddJurisdiction
jurisdictionRepository.Add(jurisdiction)
jurisdictionRepository.Commit()
End Sub
Public Function GetJurisdictionsByCompany(companyId As Integer) As List(Of CountryJurisdiction) Implements IJurisdictionService(Of CountryJurisdiction).GetJurisdictionsByCompany
Return jurisdictionRepository.GetMany(Function(j) j.CompanyID = companyId, False)
End Function
End Class
Edit: This is the context that the factory will be used in:
Public Sub AddJurisdiction(jurisdiction)
Using jurisdictionService = jurisdictionServiceFactory.getJurisdictionService(TypeName(jurisdiction))
jurisdictionService.AddJurisdiction(jurisdiction)
End Using
End Sub
Who is calling getJurisdictionService
? As long as the caller knows what Type they are requesting you can do something like this.
How about changing this:
Public Function getJurisdictionService(type As String) As Object
Return JurisdictionTypeMapper(type)
End Function
To this:
Public Function getJurisdictionService(Of T)() As IJurisdictionService(Of T)
Return DirectCast(JurisdictionTypeMapper(GetType(T)), IJurisdictionService(Of T))
End Function
And the the caller does this to get a strongly-typed service:
service = jurisdictionServiceFactory.getJurisdictionService(Of CountryJurisdictionService)()
And of course the dictionary needs to be keyed off of the Type instead of the class name:
Private JurisdictionTypeMapper As Dictionary(Of Type, Object)
Edit:
Given the new details you have provided, in that situation I often like to create base class or parent interface to create a sibling relationship between the generic classes, even if this is just for a bit of code-based documentation:
Public Interface IJurisdictionService
Inherits IDisposable
End Interface
Public Interface IJurisdictionService(Of t)
Inherits IJurisdictionService
Function GetJurisdictionsByCompany(companyId As Integer) As List(Of t)
Sub AddJurisdiction(jurisdiction As t)
End Interface
And that goes for the Jurisdiction objects as well, they could use a parent Interface or base class:
Public Interface IJurisdictionService
End Interface
Then Private JurisdictionTypeMapper As Dictionary(Of String, Object)
becomes Private JurisdictionTypeMapper As Dictionary(Of String, IJurisdictionService)