Generic class factory problem - c#

Bellow is simplified version of the code I have:
public interface IControl<T>
{
T Value { get; }
}
public class BoolControl : IControl<bool>
{
public bool Value
{
get { return true; }
}
}
public class StringControl : IControl<string>
{
public string Value
{
get { return ""; }
}
}
public class ControlFactory
{
public IControl GetControl(string controlType)
{
switch (controlType)
{
case "Bool":
return new BoolControl();
case "String":
return new StringControl();
}
return null;
}
}
The problem is in GetControl method of ControlFactory class. Because it returns IControl and I have only IControl<T> that is a generic interface. I cannot provide T because in Bool case it's going to bool and in String case it's going to be string.
Any idea what I need to do to make it work?

Just derive IControl<T> from IControl.
public interface IControl<T> : IControl
{
T Value { get; }
}
UPDATE
If I missunterstood you, and you don't want a non-generic interface, you will have to make the method GetControl() generic, too.
public IControl<T> GetControl<T>()
{
if (typeof(T) == typeof(Boolean))
{
return new BoolControl(); // Will not compile.
}
else if (typeof(T) == typeof(String))
{
return new StringControl(); // Will not compile.
}
else
{
return null;
}
}
Now you have the problem that the new controls cannot be implicitly casted to IControl<T> and you would have to make this explicit.
public IControl<T> GetControl<T>()
{
if (typeof(T) == typeof(Boolean))
{
return new (IControl<T>)BoolControl();
}
else if (typeof(T) == typeof(String))
{
return (IControl<T>)new StringControl();
}
else
{
return null;
}
}
UPDATE
Changed the cast from as IControl<T> to (IControl<T>). This is prefered because it will cause an exception if there is a bug while as IControl<T> silently returns null.

public IControl<T> GetControl<T>()
{
switch (typeof(T).Name)
{
case "Bool":
return (IControl<T>) new BoolControl();
case "String":
return (IControl<T>) new StringControl();
}
return null;
}
Update; corrected a couple of errors in the code. Heres a call to get a class:
IControl<bool> boolControl = GetControl<bool>();

The return type has to be generic, since, well, it is. Think of how you would use this. Returning a strongly typed object obviates the need for a generic factory method.
Even if you could do it, what's the gain of
IControl<bool> boolControl = controlFactory.GetControl("bool");
or, the one that would work,
IControl<bool> boolControl = controlFactory.GetControl<bool>("bool");
over a specific
IControl<bool> boolControl = controlFactory.GetBoolControl("bool");
Either way, you have the switch () at the client side. Either return an object, or have a non-typed IControl interface.

Related

Call a generic method ensuring where

I have a generic method, on the base of T type I need to call a stricter generic method, how can I do it without reflections? In the example I used as that is obviusly wrong
public T foo1<T>()
{
if(T is IMyInterface)
{
return SpecificMethod<T as IMyInterface>();
}
}
private T SpecificMethod<T>() where T : IMyInterface
{
// IMyInterface specific implementation
}
private T GenericMethod<T>()
{
// something generic to do
}
You can approach it this way:
public interface IMyInterface { }
public T Foo1<T>()
{
if (typeof(T) == typeof(IMyInterface))
{
return (T)SpecificMethod<IMyInterface>();
}
return default(T);
}
private T SpecificMethod<T>() where T : IMyInterface
{
return default(T);
}
private T GenericMethod<T>()
{
return default(T);
}
What you asked for, can't just be done.

Check if class is a subclass of specific generic

I have the following classes:
public class HtSecurePage : UserControl, IDisposable
{
}
public class HtSecureInstancePage<T1> : HtSecurePage
{
}
public partial class NormalPage : HtSecurePage
{
}
public partial class InstancePage : HtSecureInstancePage<ZlsManager>
{
}
To check if NormalPage is a subClass of HtSecurePage I use the following pattern.
if (typeof(NormalPage).BaseType == typeof(HtSecurePage))
{
}
If I use this pattern against InstancePage, it is not working.
if (typeof(InstancePage).BaseType == typeof(HtSecureInstancePage<>))
{
}
I need to know if a Type is a direct subClass of HtSecurePage or HtSecureInstancePage<>. (It's important not to check against HtSecureInstancePage<ZlsManager>!) The Type T1 is unknown.
Below function check your class' sub-class the same type supplied class. If types is generic, check operation is executed over generic type definition.
Method usage
bool isInherited = CheckIsDirectlyInherited(typeof(TestAbstract), new[] {typeof(SecondLevelAbstractClass), typeof(FirstLevelAbstract)});
Method
bool CheckIsDirectlyInherited(Type obj, Type[] baseTypes)
{
if (obj.BaseType == null)
return false;
var objGenericDefinition = obj.BaseType;
if (objGenericDefinition.IsGenericType)
{
objGenericDefinition = objGenericDefinition.GetGenericTypeDefinition();
}
foreach (Type baseType in baseTypes)
{
var baseTypeDefinition = baseType;
if (baseTypeDefinition.IsGenericType)
baseTypeDefinition = baseType.GetGenericTypeDefinition();
if (objGenericDefinition == baseTypeDefinition)
return true;
}
return false;
}
is a direct subClass of HtSecurePage
I think you already know how to do it
Console.WriteLine(typeof(HtSecureInstancePage<ZlsManager>).BaseType == typeof(HtSecurePage));
is a direct subClass of HtSecureInstancePage<>
To check it you can use something like this:
static bool IsDirectSubclassOfRawGeneric(Type parent, Type toCheck)
{
return toCheck.BaseType.IsGenericType && parent == toCheck.BaseType.GetGenericTypeDefinition();
}
...
Console.WriteLine(IsDirectSubclassOfRawGeneric(typeof(HtSecureInstancePage<>), typeof(InstancePage)));

How to modify a method to be able to return multiple types instead of just `object`?

I have this method, and I'm convinced that it's the source of another issue I'm having. I believe it's because this method returns a type of object instead of one of the three concrete types it actually returns.
Here's the method:
public object GetData(TableType type)
{
switch (type)
{
case TableType.Person:
return new Domain.PersonList(_personRepository.Get());
case TableType.Event:
return new Domain.EventList(_eventRepository.Get());
case TableType.User:
return new Domain.UserList(_userRepository.Get());
}
return null;
}
How can I modify this method to return a type other than object?
What you need is generics.
This way the method will return the type according to type.
This method for example returns TService type:
private TService GetService<TService>(ServiceInfo serviceInfo)
where TService : class, ICoordinationExecutionService
{
var service = _executionServices.FirstOrDefault(
x => x.ServiceInfo.InstanceInfo.InstanceId == serviceInfo.InstanceInfo.InstanceId
&& serviceInfo.ServiceTypeName.Equals(x.ServiceInfo.ServiceTypeName));
if (service == null)
{
throw new Exception("invalid service ");
}
return _directory.GetService<TService>(service.ServiceInfo);
}
Another possibility is to use Interfaces to guarantee that only one of your three types is returned.
public IDomainList GetData(TableType type)
{
switch (type)
{
case TableType.Person:
return new Domain.PersonList(_personRepository.Get());
case TableType.Event:
return new Domain.EventList(_eventRepository.Get());
case TableType.User:
return new Domain.UserList(_userRepository.Get());
}
return null;
}
So long as PersonList, EventList, and UserList all implement the IDomainList interface, then you are guaranteed to return on of those three types. Then in your implementation, you can determine what to do based on the specific type returned.
First, you must identify what is the "lowest common denominator" base class for the three kinds of repositories. If you do not have one, then you should create one. One way to do this would be
public abstract class repositoryBase
{
public virtual IList<repositoryBase> Get() { }
}
Then each of the three classes woudl inherit from repositoryBase:
public personRepository : repositoryBase
{
public override IList<personRepository> Get()
{
// code here to return the list
}
}
Once you have refactored the class hierarchy in this way, then you don't even need the GetData method. Where you were calling GetData, you now just call someRepository.Get();
If you are already inheriting from something else and adding a Get method to the base class is not a good fit, you can do the same thing I describe here using an Interface. Either approach, base class or interface work equally well in this case and both are good OO practice.
You could use generics to get this done,
public T GetData<T>()
{
if(typeof(T) == typeof(Domain.PersonList))
return new Domain.PersonList(_personRepository.Get());
else if (typeof(T) == typeof(Domain.EventList))
return new Domain.EventList(_eventRepository.Get());
else if (typeof(T) == typeof(Domain.UserList))
return new Domain.UserList(_userRepository.Get());
}
return default(T);
}
You can create three GetData functions, that will get the type as a parameter and return the correct type.
public List<TableType.Person> GetData(TableType.Person type)
{
return new Domain.PersonList(_personRepository.Get());
}
public List<TableType.Event> GetData(TableType.Event type)
{
return new Domain.EventList(_eventRepository.Get());
}
public List<TableType.User> GetData(TableType.User type)
{
return new Domain.UserList(_userRepository.Get());
}
The runtime will pick the correct overload according to the type of the parameter.
EDIT: I am assuming that the Domain.xxxxList functions return a list of the mentioned type in this example. It is not required, of course.
Here's a whole answer with a general solution for parameterized types for return value.
class Program
{
public enum TableType
{
Person,
Event,
User
}
class Person
{
public string Name { get; set; }
public Person(string name) { this.Name = name; }
}
class Event
{
public int EventType { get; set; }
public Event(int eventType) { this.EventType = eventType; }
}
class User
{
public string UserName { get; set; }
public User(string username) { this.UserName = username; }
}
public static T GetData<T>(TableType tableType)
{
switch (tableType)
{
case TableType.Person:
Person person = new Person("John");
return (T)Convert.ChangeType(person, typeof(T));
case TableType.Event:
Event evt = new Event(2);
return (T)Convert.ChangeType(evt, typeof(T));
case TableType.User:
User user = new User("jjesus");
return (T)Convert.ChangeType(user, typeof(T));
}
return default(T);
}
static void Main(string[] args)
{
Person person = GetData<Person>(TableType.Person);
Console.WriteLine("Person.Name {0}", person.Name);
Console.WriteLine("Hit any key to continue");
Console.ReadKey();
}
}

Cannot implicitly convert type 'Int' to 'T'

I can call Get<int>(Stat); or Get<string>(Name);
But when compiling I get:
Cannot implicitly convert type 'int' to 'T'
and the same thing for string.
public T Get<T>(Stats type) where T : IConvertible
{
if (typeof(T) == typeof(int))
{
int t = Convert.ToInt16(PlayerStats[type]);
return t;
}
if (typeof(T) == typeof(string))
{
string t = PlayerStats[type].ToString();
return t;
}
}
You should be able to just use Convert.ChangeType() instead of your custom code:
public T Get<T>(Stats type) where T : IConvertible
{
return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}
Any time you find yourself switching on a type in a generic you are almost certainly doing something wrong. Generics should be generic; they should operate identically completely independent of the type.
If T can only be int or string then don't write your code this way at all in the first place. Write two methods, one that returns an int and one that returns a string.
Actually, you can just convert it to object and then to T.
T var = (T)(object)42;
An example for bool:
public class Program
{
public static T Foo<T>()
{
if(typeof(T) == typeof(bool)) {
return (T)(object)true;
}
return default(T);
}
public static void Main()
{
bool boolValue = Foo<bool>(); // == true
string stringValue = Foo<string>(); // == null
}
}
Sometimes, this behavior is desirable. For instance, when implementing or overriding a generic method from a base class or interface and you want to add some different functionalities based on the T type.
public T Get<T>(Stats type) where T : IConvertible
{
if (typeof(T) == typeof(int))
{
int t = Convert.ToInt16(PlayerStats[type]);
return (T)(object)t;
}
if (typeof(T) == typeof(string))
{
string t = PlayerStats[type].ToString();
return (T)(object)t;
}
return (T)(object)PlayerStats[type];
}
Try this:
public T Get<T>(Stats type ) where T : IConvertible
{
if (typeof(T) == typeof(int))
{
return (T)(object)Convert.ToInt16(PlayerStats[type]);
}
if (typeof(T) == typeof(string))
{
return (T)(object)PlayerStats[type];
}
}
ChangeType is probably your best option. My solution is similar to the one provided by BrokenGlass with a bit of try catch logic.
static void Main(string[] args)
{
object number = "1";
bool hasConverted;
var convertedValue = DoConvert<int>(number, out hasConverted);
Console.WriteLine(hasConverted);
Console.WriteLine(convertedValue);
}
public static TConvertType DoConvert<TConvertType>(object convertValue, out bool hasConverted)
{
hasConverted = false;
var converted = default(TConvertType);
try
{
converted = (TConvertType)
Convert.ChangeType(convertValue, typeof(TConvertType));
hasConverted = true;
}
catch (InvalidCastException)
{
}
catch (ArgumentNullException)
{
}
catch (FormatException)
{
}
catch (OverflowException)
{
}
return converted;
}
Considering #BrokenGlass logic (Convert.ChangeType) does not support for GUID type.
public T Get<T>(Stats type) where T : IConvertible
{
return (T) Convert.ChangeType(PlayerStats[type], typeof(T));
}
Error: Invalid cast from 'System.String' to 'System.Guid'.
Instead, use below logic using TypeDescriptor.GetConverter by adding System.ComponentModel namespace.
public T Get<T>(Stats type) where T : IConvertible
{
(T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromInvariantString(PlayerStats[type])
}
Read this.
It looks like you need a TypeConverter, see this blog entry.

Converting Method to Generic Method?

I have created a Method shown below,
public BOEod CheckCommandStatus(BOEod pBo, IList<string> pProperties)
{
pBo.isValid = false;
if (pProperties != null)
{
int Num=-1;
pBo.GetType().GetProperty(pProperties[0].ToString()).GetValue(pBo, null);
if (ifIntegerGetValue(pBo.GetType().GetProperty(pProperties[0].ToString()).GetValue(pBo, null).ToString(), out Num))
{
if (Num == 1)
pBo.isValid = true;
}
}
return pBo;
}
I need to convert this method, in such a way that it should accept all Type of Objects(now i am accepting only Objects of type "BOEod").
As i am newbie to .Net so don no exactly how to use Generics. Can i accomplish this using Generics.?
Solution Something like this:
public T CheckCommandStatus<T>(T pBO, Ilist<string> pProperties){..}
Here Main thing is i need to change the Property of the Passed Object(pBO) and return it.
You would need BOEod to implement an interface which defines IsValid.
You would then add a generic constraint to your method to only accept objects implementing that interface.
public interface IIsValid
{
bool IsValid{get;set;}
}
....
public class BOEod : IIsValid
{
public bool IsValid{get;set;}
}
....
public T CheckCommandStatus<T>(T pBO, IList<string> pProperties)
where T : IIsValid{..}
public BOEod CheckCommandStatus<T>(T pBo, IList<string> pProperties) where T : IBOEod
{
pBo.isValid = false;
if (pProperties != null)
{
int Num = -1;
string propValue = pBo.GetType().GetProperty(pProperties[0].ToString()).GetValue(pBo, null).ToString();
if (ifIntegerGetValue(propValue, out Num))
{
if (Num == 1)
pBo.isValid = true;
}
}
return pBo;
}
public interface IBOEod
{
bool IsValid { get; set; }
}
All the types you want to pass to this method must implement the IBOEod interface.

Categories

Resources