I have this factory class which converts a Foo into a list of Bar objects. Foo is a very complex object which I flatten into a list of simple Bar objects. There are about 60 different bits of data that could be transformed from a Foo into a Bar. The following implementation works but there's definite scope for improvement here.
public class FooToBarsConverter
{
public List<Bar> Convert(Foo foo)
{
return Enum.GetValues(typeof(BarTypeEnum))
.Cast<BarTypeEnum>()
.Select(barType => CreateBar(foo, barType))
.Where(newBar => newBar != null)
.ToList();
}
public Bar CreateBar(Foo foo, BarTypeEnum barType)
{
switch (barType)
{
case BarTypeEnum.TypeA:
return CreateTypeA(foo);
case BarTypeEnum.TypeB:
return CreateTypeB(foo);
}
return null;
}
private Bar CreateTypeA(Foo foo)
{
return new Bar(...);
}
private Bar CreateTypeB(Foo foo)
{
return new Bar(...);
}
}
Ideally I'd like to avoid having to write a new case to the switch every time a new BarType is added. Perhaps a dictionary of types and delegate functions but that would still require a mapping of sorts? Is there any feature of the language that I can exploit to avoid this switch case a make the compiler choose the create create function?
Assuming you don't mind the factory methods being statics this does neaten it up a bit without needing the cruft of having to create ~60 more sub-classes to get the type system to do the work for me. I think the statics aren't needed if you make it a func with the factory as well but I've not got that far yet. The statics don't particularly bother me with it just being data transposition
private static readonly IDictionary<BarTypeEnum, Func<Foo, Bar>>
CreateLookup = new Dictionary<BarTypeEnum, Func<Foo, Bar>>
{
{ BarTypeEnum.TypeA, CreateTypeA },
{ BarTypeEnum.TypeB, CreateTypeB }
};
public Bar Create(Foo foo, BarTypeEnum barType)
{
Func<Foo, Bar> createDelegate;
CreateLookup.TryGetValue(barType, out createDelegate);
return createDelegate != null ? createDelegate(foo) : null;
}
private static Bar CreateTypeA(Foo foo) { ... }
private static Bar CreateTypeB(Foo foo) { ... }
Is there any feature of the language that I can exploit to avoid this switch case a make the compiler choose the create create function?
Yes. It's called polymorphism
Check this video: Jimmy Bogard - Crafting Wicked Domain Models on how an enum could be converted into a polimorhic class hierachy.
Basically you create an abstract class called BarTypeEnum that feels like an enum and create n derived types, one for each enum value. Then you could have this method
public abstract Bar CreateBar(Foo foo);
and override it in every subclass each returning a diferent subtype of Bar
e.g.
public override Bar CreateBar(Foo foo)
{
return CreateTypeA(foo);
}
BTW: The enumeration class he talks about is on NuGet as the NuGet package Enumeration
EDIT
I just checked and the nuget package class is not the same as the video. It is a Generic, nonpolimorphic way to implement it though
Not a huge fan of this because it's a bit hard to read, but you can define a custom attribute, mapping each enum value to its method. You'd use reflection to find and execute the appropriate method.
public class BarChooserAttribute : Attribute
{
public BarChooserAttribute(BarTypeEnum barType) { BarType = barType; }
public BarTypeEnum BarType { get; set; }
}
public static class CreateBarMethods
{
[BarChooser(BarTypeEnum.TypeA)]
public static Bar CreateTypeA(Foo foo)
{
return new Bar { Message = "A" };
}
[BarChooser(BarTypeEnum.TypeB)]
public static Bar CreateTypeB(Foo foo)
{
return new Bar { Message = "B" };
}
}
public static Bar CreateBar(Foo foo, BarTypeEnum barType)
{
var methodWrapper = typeof(CreateBarMethods).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Select(m => new { Method = m, Att = (BarChooserAttribute)m.GetCustomAttributes(typeof(BarChooserAttribute), false).Single() })
.Single(x => x.Att.BarType == barType);
return (Bar)methodWrapper.Method.Invoke(null, new[] { foo });
}
To improve performance, you can map the methods into a dictionary one time and retrieve them from the dictionary each time. Additionally, you can use expression trees to compile the methods into lambda expressions, so you only have to do reflection once instead of each time you make the call. Significant performance improvements, to get significantly harder-to-read code, so it's a trade-off.
Personally I don't mind a switch in a factory method, it's readable, it's neat and doesn't sarcrafice the end goal of what a factory method is for - keeping the initialization code together.
However, that being said, I wonder if a custom attribute could tidy this up a bit for you. Going on the assumption all the CreateBarX methods create an instance of Bar initializing the specific properties from Foo.
[System.AttributeUsage(System.AttributeTargets.Field)]
public class FooConverter : System.Attribute
{
public string Parameters;
public Bar GetInstance(Foo foo)
{
var propNames = String.IsNullOrEmpty(Parameters) ? new string[] { } : Parameters.Split(',').Select(x => x.Trim());
var parameters = foo.GetType().GetProperties().Where(x => propNames.Contains(x.Name)).Select(x => x.GetValue(foo));
return (Bar)Activator.CreateInstance(typeof(Bar), parameters.ToArray());
}
}
// extension helpers
public static class EnumExt
{
public static Bar GetInstance(this BarTypeEnum value, Foo foo)
{
var converterAttr = value.GetAttribute<FooConverter>();
return converterAttr != null ? converterAttr.GetInstance(foo) : null;
}
public static T GetAttribute<T>(this System.Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
var attributes = fi.GetCustomAttributes(typeof(T), false);
return attributes.Length > 0 ? (T)attributes[0] : default(T);
}
}
Which would allow you to do
public enum BarTypeEnum
{
[FooConverter] // no properties mapped
TypeA,
[FooConverter(Parameters="Prop1")] // map Prop1 from Foo to Bar
TypeB,
TypeC, // no instance
[FooConverter(Parameters="Prop1, Prop2")] // map Prop1/2 from Foo to Bar
TypeD,
TypeE // no instance
}
public List<Bar> Convert(Foo foo)
{
return Enum.GetValues(typeof(BarTypeEnum))
.Cast<BarTypeEnum>()
.Select(barType => barType.GetInstance(foo))
.Where(newBar => newBar != null)
.ToList();
}
And that's all you need!
However, there are some limitations to this approach with respect to the parameter injection, CreateInstance will only match the constructor based on a signature which matches the data type i.e.
// this will call Bar(string prop1, string prop2)
Activator.CreateInstance(typeof(Bar), new object[] { "Property1", "Property2" });
// where as this will car Bar(string prop1)
Activator.CreateInstance(typeof(Bar), new object[] { "Property2" });
The ordering is important as well
// this will call Bar(string prop1, string prop2) so Prop1 = "Property2"
Activator.CreateInstance(typeof(Bar), new object[] { "Property2", "Property1" });
However, there are ways around this - for the most part this will probably work well.
I hate 'case's and I like Generics therefore I slightly changed interface of FooToBarsConverter:
public interface IFooToBarsConverter
{
List<Bar> Convert(Foo foo);
Bar CreateBar<TBarType>(Foo foo) where TBarType : Bar;
}
There is an implementation:
public class FooToBarsConverter : IFooToBarsConverter
{
public List<Bar> Convert(Foo foo)
{
return new List<Type>
{
typeof(Bar.BarA),
typeof(Bar.BarB)
}.Select(it => CreateBar(foo, it))
.ToList();
}
public Bar CreateBar<T>(Foo foo)
where T : Bar
{
return CreateBar(foo, typeof(T));
}
private Bar CreateBar(Foo foo, Type barType)
{
return typeof(Bar).IsAssignableFrom(barType)
? (Bar)Activator.CreateInstance(barType, foo)
: null;
}
}
public class Foo
{
}
public abstract class Bar
{
private Bar(Foo foo)
{
}
public class BarA : Bar
{
public BarA(Foo foo)
: base(foo)
{
}
}
public class BarB : Bar
{
public BarB(Foo foo)
: base(foo)
{
}
}
}
... and a test that tests it:
[TestMethod]
public void TestMethod()
{
// arrange
var foo = new Foo();
var target = new FooToBarsConverter();
// act + assert
var list = target.Convert(foo);
list.Should().HaveCount(2);
list.Should().NotContainNulls();
var typeA = target.CreateBar<Bar.BarA>(foo);
typeA.Should().BeAssignableTo<Bar.BarA>();
var typeB = target.CreateBar<Bar.BarB>(foo);
typeB.Should().BeAssignableTo<Bar.BarB>();
}
Related
I'm facing a problem that I need to construct one object from multiple types and return to the front end, here is what I want(In C#).
The shape that front end wants is like this
{
...
"props" : // this is the place I need to fill-up.
...
}
For the controller, it's a custom response.
public IActionResult Index()
{
return JohnDoe.Render();
}
Behind the scenes, Render is going to get some data from two places.
public object Foo()
{
return string, int, IEnumerable, instance, etc;
}
public object Bar()
{
return string, int, IEnumerable, instance, etc;
}
I know the return statement is not valid, what I mean is that those are all the possibilities.
And here is eventually what I want.
public object Combine()
{
var foo = Foo();
var bar = Bar();
return foo + bar;
}
Again the return statement is not valid, I want to have a final object that contains both of them. It can be Dictionary<string, object> or anonymous object new {}, or something else does not matter as long as one object has both of them.
Obviously what I have here is not possible to achieve it. Here are the two options I came up with.
Just use a wrapper to wrap them, Here is what I do.
public object Combine()
{
var foo = Foo();
var bar = Bar();
return new { foo, bar };
}
I know I can have a Type rather than an anonymous object, the thing is that this will introduce two keys foo and bar, which I do not want to if possible.
Make the foo and bar only return instance. NO string, int, Array, IEnumerable etc.
If I do it in this way, things get a little bit easier. All I need to do is looping through the properties getting the values and map to either new {} or Dictionary<string, object>. This way I do not need to introduce new keys.
Update : so basically I want to avoid introducing new keys if I can, as I just want to return the original without a wrapper. That's why I came up with option 2, only instance is allowed. Let me know your thoughts, please.
You can use a Tuple:
public Tuple<Foo, Bar> Combine()
{
var foo = Foo();
var bar = Bar();
return Tuple.Create(foo, bar);
}
Or a ValueTuple:
public (Foo, Bar) Combine()
{
var foo = Foo();
var bar = Bar();
return (foo, bar);
}
Also with named fields:
public (Foo foo, Bar bar) Combine()
{
var foo = Foo();
var bar = Bar();
return (foo, bar);
}
Or, as Dennis1679 suggest, make a custom type.
How about option 3)
create a class that acts as a wrapper for Foo and Bar called FooBar ?
public class FooBar
{
public Foo Foo { get; set; }
public Bar Bar { get; set; }
}
Why?
C# is an object-oriented programming language. And it's based on the concept of wrapping pieces of data, and behavior related to that data, into special bundles, called objects, which you construct from a 'blueprint' called a class.
I think this is what you are asking
public sealed class FooBar : Foo, Bar
{
}
Unfortunately this is not possible in C#. But in essence this is what you are doing. You can do the following:
public sealed class FooBar: IFoo, IBar
{
public FooBar(IFoo foo, IBar bar)
{
///Assign its members
}
///Implement its members
}
This is what I am trying to get
(IList<Foo>)listPropertyInfo.GetValue(item)
This is how I get Foo type
listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]
This is what I tried but couldn't make it successfully
Convert.ChangeType(listPropertyInfo.GetValue(item), IList<listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]>)
and also this;
((typeof(IList<>).MakeGenericType(listPropertyInfo.GetValue(item).GetType().GenericTypeArguments.Single())))(listPropertyInfo.GetValue(item))
this is method where I am trying to implement
public static void trigger(IList<T> result)
{
foreach (var item in result)
{
foreach (var listPropertyInfo in typeof(T).GetProperties().ToList().FindAll(x => x.PropertyType.Name == typeof(IList<>).Name))
{
trigger((IList<Foo>)listPropertyInfo.GetValue(item));
}
}
}
I solved like this;
IList targetList = (IList)listPropertyInfo.GetValue(item);
Type foo = targetList.GetType().GenericTypeArguments.Single();
Type unboundGenericType = typeof(READ<>);
Type boundGenericType = unboundGenericType.MakeGenericType(foo);
MethodInfo doSomethingMethod = boundGenericType.GetMethod("trigger");
object instance = Activator.CreateInstance(boundGenericType);
doSomethingMethod.Invoke(instance, new object[] { targetList, f, properties });
If you use IList notation, Foo must be defined at compile time, you can't use expression that evaluates at runtime for Foo.
After reading your comments and and the code i would argue you are trying to do it at the wrong spot.
Here an example of how you could do this
public class MyGeneric<T>
{
public static void trigger(IList<T> result)
{
// do generic stuff where
// you do not need to know T
}
}
// this class does only explicit Foo related stuff
public class MyNONEGeneric
{
public static void trigger(IList<Foo> list)
{
// do some
}
}
class Program
{
static void Main(string[] args)
{
PersistentGenericBag<Foo> magicBag = myMagic<Foo>();
// call your generic which do some general list related stuff
MyGeneric<Foo>.trigger(list);
// call your none generic which do some foo related stuff
MyNONEGeneric.trigger(list);
}
}
like you can see i did some sort of "separation of concerns" / "single responsibility principle" here.
Every thing does only "one" thing. so if you are in need to change something you will know exactly where.
Also if you are working in a Team you can tell Person A to do the MyGeneric<T> and Person B to do the MyNONEGeneric
So I have this class:
public class Foo<T> where T : ???
{
private T item;
public bool IsNull()
{
return item == null;
}
}
Now I am looking for a type constraint that allows me to use everything as type parameter that can be null. That means all reference types, as well as all the Nullable (T?) types:
Foo<String> ... = ...
Foo<int?> ... = ...
should be possible.
Using class as the type constraint only allows me to use the reference types.
Additional Information:
I am writing a pipes and filters application, and want to use a null reference as the last item that passes into the pipeline, so that every filter can shut down nicely, do cleanup, etc...
If you are willing to make a runtime check in Foo's constructor rather than having a compile-time check, you can check if the type is not a reference or nullable type, and throw an exception if that's the case.
I realise that only having a runtime check may be unacceptable, but just in case:
public class Foo<T>
{
private T item;
public Foo()
{
var type = typeof(T);
if (Nullable.GetUnderlyingType(type) != null)
return;
if (type.IsClass)
return;
throw new InvalidOperationException("Type is not nullable or reference type.");
}
public bool IsNull()
{
return item == null;
}
}
Then the following code compiles, but the last one (foo3) throws an exception in the constructor:
var foo1 = new Foo<int?>();
Console.WriteLine(foo1.IsNull());
var foo2 = new Foo<string>();
Console.WriteLine(foo2.IsNull());
var foo3= new Foo<int>(); // THROWS
Console.WriteLine(foo3.IsNull());
I don't know how to implement equivalent to OR in generics. However I can propose to use default key word in order to create null for nullable types and 0 value for structures:
public class Foo<T>
{
private T item;
public bool IsNullOrDefault()
{
return Equals(item, default(T));
}
}
You could also implement you version of Nullable:
class MyNullable<T> where T : struct
{
public T Value { get; set; }
public static implicit operator T(MyNullable<T> value)
{
return value != null ? value.Value : default(T);
}
public static implicit operator MyNullable<T>(T value)
{
return new MyNullable<T> { Value = value };
}
}
class Foo<T> where T : class
{
public T Item { get; set; }
public bool IsNull()
{
return Item == null;
}
}
Example:
class Program
{
static void Main(string[] args)
{
Console.WriteLine(new Foo<MyNullable<int>>().IsNull()); // true
Console.WriteLine(new Foo<MyNullable<int>> {Item = 3}.IsNull()); // false
Console.WriteLine(new Foo<object>().IsNull()); // true
Console.WriteLine(new Foo<object> {Item = new object()}.IsNull()); // false
var foo5 = new Foo<MyNullable<int>>();
int integer = foo5.Item;
Console.WriteLine(integer); // 0
var foo6 = new Foo<MyNullable<double>>();
double real = foo6.Item;
Console.WriteLine(real); // 0
var foo7 = new Foo<MyNullable<double>>();
foo7.Item = null;
Console.WriteLine(foo7.Item); // 0
Console.WriteLine(foo7.IsNull()); // true
foo7.Item = 3.5;
Console.WriteLine(foo7.Item); // 3.5
Console.WriteLine(foo7.IsNull()); // false
// var foo5 = new Foo<int>(); // Not compile
}
}
I ran into this issue for a simpler case of wanting a generic static method that could take anything "nullable" (either reference types or Nullables), which brought me to this question with no satisfactory solution. So I came up with my own solution which was relatively easier to solve than the OP's stated question by simply having two overloaded methods, one that takes a T and has the constraint where T : class and another that takes a T? and has where T : struct .
I then realized, that solution can also be applied to this problem to create a solution that is checkable at compile time by making the constructor private (or protected) and using a static factory method:
//this class is to avoid having to supply generic type arguments
//to the static factory call (see CA1000)
public static class Foo
{
public static Foo<TFoo> Create<TFoo>(TFoo value)
where TFoo : class
{
return Foo<TFoo>.Create(value);
}
public static Foo<TFoo?> Create<TFoo>(TFoo? value)
where TFoo : struct
{
return Foo<TFoo?>.Create(value);
}
}
public class Foo<T>
{
private T item;
private Foo(T value)
{
item = value;
}
public bool IsNull()
{
return item == null;
}
internal static Foo<TFoo> Create<TFoo>(TFoo value)
where TFoo : class
{
return new Foo<TFoo>(value);
}
internal static Foo<TFoo?> Create<TFoo>(TFoo? value)
where TFoo : struct
{
return new Foo<TFoo?>(value);
}
}
Now we can use it like this:
var foo1 = new Foo<int>(1); //does not compile
var foo2 = Foo.Create(2); //does not compile
var foo3 = Foo.Create(""); //compiles
var foo4 = Foo.Create(new object()); //compiles
var foo5 = Foo.Create((int?)5); //compiles
If you want a parameterless constructor, you won't get the nicety of overloading, but you can still do something like this:
public static class Foo
{
public static Foo<TFoo> Create<TFoo>()
where TFoo : class
{
return Foo<TFoo>.Create<TFoo>();
}
public static Foo<TFoo?> CreateNullable<TFoo>()
where TFoo : struct
{
return Foo<TFoo?>.CreateNullable<TFoo>();
}
}
public class Foo<T>
{
private T item;
private Foo()
{
}
public bool IsNull()
{
return item == null;
}
internal static Foo<TFoo> Create<TFoo>()
where TFoo : class
{
return new Foo<TFoo>();
}
internal static Foo<TFoo?> CreateNullable<TFoo>()
where TFoo : struct
{
return new Foo<TFoo?>();
}
}
And use it like this:
var foo1 = new Foo<int>(); //does not compile
var foo2 = Foo.Create<int>(); //does not compile
var foo3 = Foo.Create<string>(); //compiles
var foo4 = Foo.Create<object>(); //compiles
var foo5 = Foo.CreateNullable<int>(); //compiles
There are few disadvantages to this solution, one is that you may prefer using 'new' to construct objects. Another is that you won't be able to use Foo<T> as a generic type argument for a type constraint of something like: where TFoo: new(). Finally is the bit of extra code you need here which would increase especially if you need multiple overloaded constructors.
As mentioned, you cannot have a compile-time check for it. Generic constraints in .NET are severely lacking, and do not support most scenarios.
However I consider this to be a better solution for run-time checking. It can be optimized at JIT compilation time, since they're both constants.
public class SomeClass<T>
{
public SomeClass()
{
// JIT-compile time check, so it doesn't even have to evaluate.
if (default(T) != null)
throw new InvalidOperationException("SomeClass<T> requires T to be a nullable type.");
T variable;
// This still won't compile
// variable = null;
// but because you know it's a nullable type, this works just fine
variable = default(T);
}
}
Such a type constraint is not possible. According to the documentation of type constraints there is not constraint that captures both the nullable and the reference types. Since constraints can only be combined in a conjunction, there is no way to create such a constraint by combination.
You can, however, for your needs fall back to an unconstraint type parameter, since you can always check for == null. If the type is a value type the check will just always evaluate to false. Then you'll possibly get the R# warning "Possible compare of value type with null", which is not critical, as long as the semantics is right for you.
An alternative could be to use
object.Equals(value, default(T))
instead of the null check, since default(T) where T : class is always null. This, however, means that you cannot distinguish weather a non-nullable value has never been set explicitly or was just set to its default value.
I use
public class Foo<T> where T: struct
{
private T? item;
}
If you only want to allow nullable value types and reference types, and disallow non-nullable value types, then I think you're out of luck as of C# 9.
I am writing a pipes and filters application, and want to use a null reference as the last item that passes into the pipeline, so that every filter can shut down nicely, do cleanup, etc...
In other words, you need to reserve a special value that indicates the end-of-stream.
Consider creating a wrapper type that provides this. It'd be similar to how Nullable<T> is implemented, and has the additional benefit of allowing a non-end-of-stream null value to be transmitted, should that be useful.
public readonly struct StreamValue<T>
{
public bool IsEndOfStream { get; }
public T Value { get; }
}
public class Foo<T>
{
private T item;
public Foo(T item)
{
this.item = item;
}
public bool IsNull()
{
return object.Equals(item, null);
}
}
var fooStruct = new Foo<int?>(3);
var b = fooStruct.IsNull();
var fooStruct1 = new Foo<int>(3);
b = fooStruct1.IsNull();
var fooStruct2 = new Foo<int?>(null);
b = fooStruct2.IsNull();
var fooStruct3 = new Foo<string>("qqq");
b = fooStruct3.IsNull();
var fooStruct4 = new Foo<string>(null);
b = fooStruct4.IsNull();
This is my Scenario:
public class Foo
{
private readonly List<Lazy<IAnimal>> _animals;
public Foo(List<Lazy<IAnimal>> animals )
{
_animals = animals;
}
public void Bark()
{
//Line: *
var dog = _animals.First(p => p.GetType() == typeof (Dog)).Value;
}
Public void Mio()
{
//Line: *
var dog = _animals.First(p => p.GetType() == typeof (Cat)).Value;
}
}
public class Dog:IAnimal
{
}
public class Cat:IAnimal
{
}
public interface IAnimal
{
}
Questions:
Here The list of Animals are Lazily injected into the class Foo.
I want to do something like Line * with Ninject. As you may know the problem is that before resolving a class, GetType() returns Null. So how can I resolve just one of the Items in the list whenever I want?
Can Ninject do such a thing at all or I have to change my DI Container?
This is a chicken and the egg problem: you don't know the type unless you get the value. You can only solve this by adding extra information to the list that is known before hand.
This is a good fit for Lazy<T, TMetadata> which is part of the System.ComponentModel.Composition assembly:
public class Foo
{
private readonly List<Lazy<IAnimal, Type>> _animals;
public Foo(List<Lazy<IAnimal, Type>> animals)
{
_animals = animals;
}
public void Bark()
{
var dog = _animals.First(p => p.Metadata == typeof(Dog)).Value;
}
}
Update
As I said in the comments, I'm no Ninject expert, but most things can be done with a framework, even when there is no built-in support for it. This is what I think your registration would look like. I might have the Ninject syntax wrong, but it would look a bit like this:
var list = new List<Lazy<IAnimal, Type>>();
list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Dog>(), typeof(Dog)));
list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Pussy>(), typeof(Pussy)));
list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Horse>(), typeof(Horse)));
kernel.Bind<List<Lazy<IAnimal, Type>>().ToConstant(list);
You can use the OfType extension method provided in the System.Linq namespace.
var dog = _animals.OfType<Dog>().First();
Greetings everyone!
I'll try to make my problem simple: I have an enum to select which ObjType I should use (ObjTypeA and ObjTypeB both inherits from ObjType). So I created a method to extend the given enum, in order to return a new instance according to the selected property in the enum, like follows in the code. I think it works more or less like a factory design pattern. So far so good, but eventually, like in the class MyClass, I may attempt to create n instances of ObjTypeA or ObjTypeB, but I'll have to face the if statement everytime I call the GetObjTypeInstance() method. So:
Can an enum return an instance, something like: public enum EObjType { ObjTypeA = new ObjTypeA(), ObjTypeB = new ObjTypeB() }? Actually, it'd be better to append some GetInstance() method to the ObjTypeA and to the ObjTypeB options in the enum. If there's a way to do this, how can I do it? Doing this I'd avoid those if statements every while step.
Is there any other (and better) way to this this (if you understood my problem...)? How?
Thanks in advance!
Follow the example code:
public static class EObjTypeExt
{
public static ObjType GetObjTypeInstance(this EObjType ot)
{
if (ot == EObjType.ObjTypeA)
{
return new ObjTypeA();
}
else if (ot == EObjType.ObjTypeB)
{
return new ObjTypeB();
}
throw new ArgumentOutOfRangeException("unrecognized type!");
}
}
public enum EObjType { ObjTypeA, ObjTypeB }
public class MyClass
{
ObjType[] obj { get; set; }
public MyClass(EObjType otEnum, int n)
{
this.obj = new ObjType[n];
int i = 0;
while (i < n)
{
this.obj[i] = otEnum.GetObjTypeInstance();
i++;
}
}
}
You'll have to byte this apple somewhere.
Maybe replace the if/elseif chain with switch statement, they work great with enums.
Instead of using an enum, I would use a class that looks like an enum:
public class EObjType {
public static readonly EObjType ObjTypeA = new EObjType(() => (ObjType)(new ObjTypeA));
public static readonly EObjType ObjTypeB = new EObjType(() => (ObjType)(new ObjTypeB));
private readonly Func<ObjType> generator;
private EObjType(Func<ObjType> generator) {
this.generator = generator;
}
public ObjType GetInstanceOfObjType() {
return generator();
}
}
You can then use it exactly as you have been the enum.
EObjType otEnum = EObjType.ObjTypeA;
ObjType obj = otEnum.GetInstanceOfObjType();
You need to use a factory or other creational design pattern.
For instance, you could hold a dictionary from enum key to type value to get the desired class type using selected enum value. Then use reflection to create a new instance (object) of received type.
Initialize static dictionary's values using static constructor of factory class. You can enter the values manually or better yet, load possible values from a config file.
I'm not sure that I'd really advocate this approach, but you could call the enum ToString() method, treat that as your class name and use reflection to instantiate an object of that type.
One advantage of this would be that you could reflect and get the type once, then call the constructor n times in your loop.
As Danny Varod points out, a dictionary mapping your enum values to their Types (or to functions that create those types) would allow you to avoid if statements. Since enum is really just an integer underneath, an array would be more memory and time efficient, but readability is probably most important here.
You could create a factory that allows registration of functions that map to your enumeration, you could that use some sort of registration process to register your different enumerations
public class ObjectFactory
{
private readonly Dictionary<MyObjectType, Func<MyObject>> _store = new Dictionary<MyObjectType, Func<MyObject>>();
public void Register<T>(MyObjectType type) where T: MyObject, new()
{
this.Register(type, () => new T());
}
public void Register(MyObjectType type, Func<MyObject> factory)
{
_store.Add(type, factory);
}
public MyObject CreateInstance(MyObjectType type)
{
Func<MyObject> factory;
if(_store.TryGetValue(type, out factory))
{
return factory.Invoke();
}
return null;
}
}
public enum MyObjectType { A, B }
public class MyObject {}
public class MyObjectA : MyObject {}
public class MyObjectB : MyObject {}
Usage as follows
var factory = new ObjectFactory();
factory.Register<MyObjectA>(MyObjectType.A);
factory.Register<MyObjectB>(MyObjectType.B);
var a = factory.CreateInstance(MyObjectType.A);
var b = factory.CreateInstance(MyObjectType.B);
Assert.IsInstanceOf(typeof(MyObjectA), a);
Assert.IsInstanceOf(typeof(MyObjectB), b);
You could use Activator.CreateInstance.
public class ObjType {}
public class ObjTypeA : ObjType {}
public class ObjTypeB : ObjType {}
public enum EObjType { ObjTypeA, ObjTypeB }
public static class EObjTypeExt
{
public static ObjType GetObjTypeInstance( EObjType ot)
{
object o = Activator.CreateInstance(null,ot.ToString());
return (ObjType)o;
}
}