Reputation: 10627
I have this code in my base controller in an MVC app:
protected LookUpClient GetLookupClient() {
return new LookUpClient(CurrentUser);
}
protected AdminClient GetAdminClient() {
return new AdminClient(CurrentUser);
}
protected AffiliateClient GetAffiliateClient() {
return new AffiliateClient(CurrentUser);
}
protected MembershipClient GetMembershipClient() {
return new MembershipClient(CurrentUser);
}
protected SecurityClient GetSecurityClient() {
return new SecurityClient();
}
protected ChauffeurClient GetChauffeurClient() {
return new ChauffeurClient(CurrentUser);
}
Can I somehow consolidate it using a generic method?
Update: SecurityClient()'s different constructor is deliberate. It does not take a user.
Upvotes: 2
Views: 186
Reputation: 39836
You can condense them all down to:
protected T GetClient<T>(params object[] constructorParams)
{
return (T)Activator.CreateInstance(typeof(T), constructorParams);
}
Call it using:
AdminClient ac = GetClient<AdminClient>(CurrentUser);
LookupClient lc = GetClient<LookupClient>(CurrentUser);
SecurityClient sc = GetClient<SecurityClient>();
etc.
If you had all of your clients utilizing the CurrentUser (currently your example suggests that SecurityClient does not), you could remove the parameter from the method and have just:
protected T GetClient<T>()
{
return (T)Activator.CreateInstance(typeof(T), CurrentUser);
}
Which simplifies your calls:
AdminClient ac = GetClient<AdminClient>();
But then you lose the ability to use it on clients that don't require the CurrentUser context...
Addendum: In response to your comment regarding the requirement of a parameterless constructor. I've got some demo code that I've tested to prove there isn't a requirement for a parameterless constructor:
public class UserContext
{
public string UserName { get; protected set; }
public UserContext(string username)
{
UserName = username;
}
}
public class AdminClient
{
UserContext User { get; set; }
public AdminClient(UserContext currentUser)
{
User = currentUser;
}
}
public class SecurityClient
{
public string Stuff { get { return "Hello World"; } }
public SecurityClient()
{
}
}
class Program
{
public static T CreateClient<T>(params object[] constructorParams)
{
return (T)Activator.CreateInstance(typeof(T), constructorParams);
}
static void Main(string[] args)
{
UserContext currentUser = new UserContext("BenAlabaster");
AdminClient ac = CreateClient<AdminClient>(currentUser);
SecurityClient sc = CreateClient<SecurityClient>();
}
}
This code runs without any exceptions and will create the AdminClient which doesn't have a paremeterless constructor, and will also create the SecurityClient which only has a parameterless constructor.
Upvotes: 6
Reputation: 27927
I try to avoid using reflection when it comes to generics, so if its possible to redesign your XYclient classes with a common base class or an interface i would do that. sample:
public interface IClient
{
CurrentUser CurrentUser { get; set; }
}
public class LookUpClient : IClient
{
public CurrentUser CurrentUser {get;set;}
}
public class AffiliateClient : IClient
{
public CurrentUser CurrentUser { get; set; }
}
class Program
{
private static T GetClient<T>() where T : IClient, new()
{
T client = new T();
client.CurrentUser = CurrentUser;
return client;
}
static void Main(string[] args)
{
var lookup = GetClient<LookUpClient>();
var affiliate = GetClient<AffiliateClient>();
}
}
Upvotes: 0
Reputation: 23157
I had a thought about using dynamic
to solve this. If you could change your clients to expose CurrentUser as a property, you could potentially do something like this:
protected T GetClient<T>(int CurrentUser) where T : new()
{
T client = new T();
dynamic retval = client;
retval.CurrentUser = CurrentUser;
return retval;
}
I don't think this is any better than the suggestions above, but just presented as a different approach.
Upvotes: 1
Reputation: 144136
You could use reflection, although this depends on the created type having a matching constructor:
protected T GetClient<T>()
{
ConstructorInfo ci = typeof(T).GetConstructor(new[] { typeof(User) });
return (T)ci.Invoke(new object[] { this.CurrentUser });
}
Upvotes: 0