I'm trying to figure what would be the best way to call a function off of a generic class.
public T Create<T>(T obj)
{
switch (obj.GetType().Name)
{
case "Bank":
(new Bank()).Create(obj);
break;
case "Bar":
(new Bar()).Create(obj);
break;
case "Beer":
(new Beer()).Create(obj);
break;
default:
(new Broke()).Create(obj);
break;
}
return obj;
}
I asked my good friend Alexa, Siri, and Google, but they weren't all that helpful. Normally I'm able to get all the answers I need from one of them...
2 days later
I did a poor job of explaining at the time. But I went ahead with the giant switch and a simplified version looks like this. With the CreateEntity function overloaded accepting each of the different classes.
public Entry Create<T>(T obj, ObjBuilder builder)
{
Entry entry;
switch (obj)
{
case Profile p:
entry = builder.CreateEntity(p);
break;
case Area a:
entry = builder.CreateEntity(a);
break;
case Credential c:
entry = builder.CreateEntity(c);
break;
case Device d:
entry = builder.CreateEntity(d);
break;
}
return entry;
}
CodePudding user response:
A simple solution is to have all your entities implement the same interface.
public interface ICreateable<T> {
T Create();
}
public class Bank : ICreateable<Bank> {
public Bank Create()
{
return new Bank();
}
// ...
}
Not really sure what the use case is though.
CodePudding user response:
I'd suggest you look at using a Dictionary<Type, Delegate>
to make this work. It might seem complicated, but it gives you the ability to add any number of types at run-time.
Here's the code:
private Dictionary<Type, Delegate> _creators = new Dictionary<Type, Delegate>();
public Entry Create<T>(T obj, ObjBuilder builder) =>
_creators.ContainsKey(typeof(T))
? ((Func<ObjBuilder, T, Entry>)_creators[typeof(T)])(builder, obj)
: null;
public void Register<T>(Func<ObjBuilder, T, Entry> factory)
{
_creators[typeof(T)] = factory;
}
Now just register your factories:
Register<Profile>((b, x) => b.CreateEntity(x));
Register<Area>((b, x) => b.CreateEntity(x));
Register<Credential>((b, x) => b.CreateEntity(x));
Register<Device>((b, x) => b.CreateEntity(x));
Easy.
Or you can hard-code the dictionary like this:
private Dictionary<Type, Delegate> _creators = new Dictionary<Type, Delegate>()
{
{ typeof(Profile), (Func<ObjBuilder, Profile, Entry>)((b, x) => b.CreateEntity(x)) },
{ typeof(Area), (Func<ObjBuilder, Area, Entry>)((b, x) => b.CreateEntity(x)) },
{ typeof(Credential), (Func<ObjBuilder, Credential, Entry>)((b, x) => b.CreateEntity(x)) },
{ typeof(Device), (Func<ObjBuilder, Device, Entry>)((b, x) => b.CreateEntity(x)) },
};
Or you can do a combination of both.
Here's the way to do this with the original code you had:
void Main()
{
Register<Bank>(obj => (new Bank()).Create(obj));
Register<Bar>(obj => (new Bar()).Create(obj));
Register<Beer>(obj => (new Beer()).Create(obj));
Register<Broke>(obj => (new Broke()).Create(obj));
}
private Dictionary<Type, Delegate> _creators = new Dictionary<Type, Delegate>();
public T Create<T>(T obj)
{
if (_creators.ContainsKey(typeof(T)))
{
((Func<T, T>)_creators[typeof(T)])(obj);
}
return obj;
}
public void Register<T>(Action<T> action)
{
_creators[typeof(T)] = action;
}
CodePudding user response:
Can you try to slice the problem the following way?
public class EntryData
{
int X { get; }
int Y { get; }
}
public interface IEntryData {
EntryData GetEntryData();
}
public class Profile: IEntryData {
...
public EntryData AsEntry();
}
public class Area: IEntryData {
...
public EntryData AsEntry();
}
...
Option 1:
public Entry Create(object obj, ObjBuilder builder) {
if(obj is not IEntryData) {...}
IEntryData entryData = obj as IEntryData;
builder.CreateEntity(entryData);
}
Option 2:
public Entry Create(IEntryData obj, ObjBuilder builder)
=> builder.CreateEntity(entryData);
...
class ObjBuilder {
Entry CreateEntity(IEntryData entryData) {
// Other things
var extra = ...
return new Entry(
x: entryData.X,
y: entryData.Y,
z: extra.Z)
}