i'm trying to do fancy stuff like this:
i have following code:
public interface IMyInterface
{
void Method1();
}
public interface IClassFactory
{
object GetObject();
}
public interface IGenericClassFactory<T> where T: IMyInterface
{
T GetObject();
}
public class MyClass : IMyInterface
{
public void Method1()
{
Console.WriteLine("Medota 1");
}
}
public class MyFactory : IClassFactory
{
public object GetObject()
{
return new MyClass();
}
}
public class MyGenericFactory<T> : IGenericClassFactory<T> where T : IMyInterface, new()
{
public T GetObject()
{
// T t = new T();
//return t;
//var ctor = typeof(T).GetConstructor(new Type[0]);//1] { typeof(int) });
//if (ctor != null)
//{
// return (T)ctor.Invoke(new object[0]); // new object[1] { 5});
// //return Activator.CreateInstance<T>(); //to samo co wyzej tylko nie jest bezpieczne
//}
//throw new InvalidOperationException("T nie posiada domyślnego konstruktora");
// return Activator.CreateInstance<T>(); //bez parametrów
// return (T)Activator.CreateInstance(typeof(T), 5, "EOG", new object()); // z parametrami
return new T();
}
}
static void Main(string[] args)
{
IClassFactory factory;
factory = new MyFactory();
IGenericClassFactory<IMyInterface> genFactory;
genFactory = new MyGenericFactory<MyClass>(); //Do not compile!
MyClass obj = genFactory.GetObject() as MyClass;
obj.Method1();
Console.ReadKey();
}
I can do this like:
IGenericClassFactory<IMyInterface> genFactory;
genFactory = new MyGenericFactory<MyClass>();
//so i can chose object to create
but i think it is pointless because i want to have Factory of more then one object.
Can u help me?
Thx in advance
You should not make your factory class generic but the method GetObject should be generic:
public T GetObject<T>() where T: IMyInterface, new()
Then:
static void Main(string[] args)
{
var factory = new MyFactory();
var obj = factory.GetObject<MyClass>();
obj.Method1();
Console.ReadKey();
}
So all in all you should get rid of your generic code and simply modify your MyFactory class
public class MyFactory : IClassFactory
{
public T GetObject<T>()
{
//TODO - get object of T type and return it
return new T();
}
}
By the way - I am not sure what is the purpose of having this generic implementation? Does it make any sense from the perspective of the usage of Factory pattern?
Related
I'm having a problem when trying to register my types using their static constructors, with the following factory:
public class Factory<T>
{
public static Factory<T> Instance { get { return _instance; } }
private static Factory<T> _instance = new Factory<T>();
private Factory() { }
static Factory() { }
static Dictionary<string, Type> _registeredType = new Dictionary<string, Type>();
public void Register(string id, T obj)
{
if (obj.GetType().IsAbstract || obj.GetType().IsInterface)
throw new ArgumentException("Cannot create instance of interface or abstract class");
_registeredType.Add(id, obj.GetType());
}
public T Create(string id, params object[] parameters)
{
Type type;
if(!_registeredType.TryGetValue(id, out type))
throw new UnsupportedShapeException(id);
return (T)Activator.CreateInstance(type, parameters);
}
}
Then if I use a static constructor for registration it doesn't work:
public interface IShape
{
string print { get; }
}
public class Circle : IShape
{
static Circle()
{
Factory<IShape>.Instance.Register("Circle", new Circle());
}
public string print
{
get
{
return "Circle";
}
}
}
Where am I going wrong? The factory appears to set up fine but I just can't get the ctor to work. Cheers.
It's not an answer but an advice. First, when you use generic class actually CLR creates class for every implementation. This classes will have different static variables and you can not use one factory for all classes. The good news is that you can use generic methods instead of generic class. And you even do not need to create an instance of T object:
public class Factory
{
public static Factory Instance { get { return _instance; } }
private static Factory _instance = new Factory();
private Factory() { }
static Dictionary<string, Type> _registeredType = new Dictionary<string, Type>();
public void Register<T>(string id)
{
var type = typeof(T);
if (type.IsAbstract || type.IsInterface)
throw new ArgumentException("Cannot create instance of interface or abstract class");
_registeredType.Add(id, type);
}
public T Create<T>(string id, params object[] parameters)
{
Type type;
if(!_registeredType.TryGetValue(id, out type))
throw new UnsupportedShapeException(id);
return (T) Activator.CreateInstance(type, parameters);
}
}
Now you can use Factory to register and resolve objects:
Factory.Instance.Register<Circle>("Circle");
var firstCircle = Factory.Instance.Create<Circle>("Circle");
var secondCircle = Factory.Instance.Create<IShape>("Circle");
I am not 100% sure I know what you are going after, however, it would probably be best to make controller'esqe classes that contain your factory instantiation. However, constructor injection will not work on static classes or descendants.
public static class StaticFactoryClassController
{
private static readonly IStaticFactoryService service=AppServiceFactory.Instance.Create<IStaticFactoryService>();
public static void DoSomething()
{
Service srv = new StaticFactoryClassService(service);
srv.DoSomething();
}
}
And with that you could create a service class--
public class StaticFactoryClassService
{
private readonly IStaticFactoryService service;
public StaticFactoryClassService(IStaticFactoryService service)
{
this.service = service;
}
public void DoSomething()
{
this.service.DoSomething();
}
}
And finally your binding interface--
public interface IStaticFactoryService
{
DoSomething();
}
I have an Author object (extends IModel) that is sent to a generic method:
IModel author = new Author() { ... };
(new Base).Method(author);
and the Base class method:
public void Method<T>(T obj) where T : IModel {
//does stuff
AddToList(obj);
}
private void AddToList<T>(T obj) where T : IModel {
if(obj is Author)
{
var temp = (Author)obj; // <-- this is where the error comes up
//does stuff
}
else if(obj is SomethingElse)
//...
}
How can I cast back from a generic type (T) back to the main Type (Author or anything else that the typeof matches?
Try replacing the line with obj as Auther. It should work.
From https://msdn.microsoft.com/en-us/library/aa479858.aspx
Looks like you need a temporary object first.
class MyOtherClass
{...}
class MyClass<T>
{
void SomeMethod(T t)
{
object temp = t;
MyOtherClass obj = (MyOtherClass)temp;
}
}
I have the following code defined in terms of hierarchy -
public interface ISomeInterface
{
bool DoSomething();
}
public abstract class AbsActualWorker : ISomeInterface
{
public bool DoSomething()
{
Console.WriteLine("DoSomething");
throw new Exception("throwing exception for the sake of it!");
}
public abstract bool DoSomething2();
}
public class ActualWorker : AbsActualWorker
{
public override bool DoSomething2()
{
Console.WriteLine("DoSomething2");
Thread.Sleep(1000);
return true;
//throw new Exception("throwing exception for the sake of it!");
}
}
Im trying to resolve to the ActualWorker level and execute its DoSomething2
var container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<AbsActualWorker, ActualWorker>();
container
.RegisterType<ISomeInterface, ActualWorker>(new Interceptor(new InterfaceInterceptor()),
new InterceptionBehavior(new MyLoggerBehavior())
);
var instance = container.Resolve<ISomeInterface>();
if (instance != null)
{
instance.DoSomething();
}
Code happily resolves and can call
instance.DoSomething();
When I cast instance to ActualWorker Im getting null. Id like to use call DoSomething2.
public class MyLoggerBehavior : IInterceptionBehavior
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var returnValue = getNext()(input, getNext);
if (returnValue.Exception != null)
{
Console.WriteLine("Exception occurred!!");
}
else
{
Console.WriteLine("Method {0} returned {1}", input.MethodBase, returnValue.ReturnValue);
}
return returnValue;
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute
{
get { return true; }
}
}
Your problem is in interceptor. Due to
container.RegisterType<ISomeInterface, ActualWorker>(new Interceptor(new InterfaceInterceptor()), new InterceptionBehavior(new MyLoggerBehavior()));
You get for ISomeInterface not ActualWorker type but a wrappertype that realize ISomeInterface. This type cannot be casted to ActualWorker.
If you work with Dependency injection you should not call methods that is not in public interface that you inject. If you need to cast variable of interface to concrete realization it means that you do something wrong.
If I have a method that takes any object as a parameter I will like to create another object of the same type. In other words if I have an object of type Person I will like to cast or instantiate a new object of type person. If that object is an Animal in the other hand I will like to instantiate a new object from that class. All this without using an if or switch statement. let me show you what I mean
class Animal {
public virtual void Talk()
{
Console.WriteLine("-");
}
}
class Dog :Animal
{
public override Talk()
{
Console.WriteLine("Woof");
}
}
class Cat : Animal
{
public override void Talk()
{
Console.WriteLine("Miau");
}
}
public static void Main(String[] args)
{
Animal a = generateRandomAnimal();
Animal b; // I want to institate object b without needing an if statement or a switch
// I want to avoid this...
if (a is Dog)
b = new Dog();
else if (a is Cat)
b = new Cat();
else
b = new Animal();
// if I new what b would be a Cat in advance i know I could do :
b = (Cat)b;
// if am looking for something like
b=(a.GetType())b; // this gives a compile error
}
static Animal generateRandomAnimal()
{
switch (new Random().Next(1, 4))
{
case 1:
return new Animal();
case 2:
return new Dog();
default:
return new Cat();
}
}
Edit
Thanks to kprobst I ended up with:
class Person
{
public string Address { get; set; }
public string Name { get; set; }
}
class Animal
{
public virtual void Talk()
{
Console.WriteLine("-");
}
}
class Car
{
public int numberOfDoors { get; set; }
}
static object generateRandomObject()
{
switch (new Random().Next(1, 4))
{
case 1:
return new Person();
case 2:
return new Car();
default:
return new Animal();
}
}
public static void Main(String[] args)
{
object o = generateRandomObject();
object newObject; // i want new object to be of the same type as object o
if (o is Animal)
newObject = new Animal();
if (o is Person)
newObject = new Person();
if (o is Car)
newObject = new Car();
Type t = o.GetType();
var b = Activator.CreateInstance(t);
//.....etc
In my example not all objects inherited from the same class. It is the first time I see the a real benefit from the var keword. I know it is helpful but I just have use it to make my code smaller and more readable... but in this case it really helps out!
Something like this:
Type t = a.GetType();
Animal b = (Animal) Activator.CreateInstance(t);
(didn't actually test that)
If I were in your shoes, I would implement the IClonable interface and just call :
Animal b = a.Clone();
You could create a method called "CreateNew()" and create a empty instance of the current object type. You can do this by making the method virtual or use this approach:
public Animal CreateNew()
{
return (Type)Activator.CreateInstance(GetType());
}
Just have an overridable method on Animal called Duplicate() or something, and return a new instance.
For example:
class Animal //should this class really be abstract?
{
public virtual void Talk()
{
Console.WriteLine("-");
}
public virtual Animal Duplicate()
{
return new Animal();
}
}
class Dog : Animal
{
public override void Talk()
{
Console.WriteLine("Woof");
}
public override Animal Duplicate()
{
return new Dog();
}
}
class Cat : Animal
{
public override void Talk()
{
Console.WriteLine("Miau");
}
public override Animal Duplicate()
{
return new Cat();
}
}
Also, please note the change for the Talk() method, by making it virtual and then overriding it in the sub classes.
You can't do "dynamic type-casting" like that.
I would suggest using a bit of object oriented programming. Try implementing the following method in every class that inherits from Animal:
In Animal:
public abstract Animal GenerateAnimal();
In Cat:
public override Animal GenerateAnimal()
{
return new Cat();
}
In Dog:
public override Animal GenerateAnimal()
{
return new Dog();
}
Example 1 (does not compile):
void Main()
{
var c = new C<D>();
c.M.F();
}
class C<T>
{
T _m = null;
public T M { get {
if(_m == null) _m = new T();
return _m;
} }
}
class D
{
public void F() { Console.WriteLine ("i was created"); }
}
Result:
Cannot create an instance of the variable type 'T' because it does not have the new() constraint
Example 2 (works):
void Main()
{
var c = new C<D>();
c.M.F();
}
class C<T>
{
Lazy<T> _m = new Lazy<T>();
public T M { get { return _m.Value; } }
}
class D
{
public void F() { Console.WriteLine ("i was created"); }
}
Result:
i was created
If you delve into the source code, you'll see that Lazy<T> ultimately uses Activator:
return new Lazy<T>.Boxed((T)Activator.CreateInstance(typeof(T)));
This is just a shortcut for using reflection. Since it's not instantiating the type via the actual generic type argument (new T()) but rather invoking the constructor through reflection, no where T : new() constraint is needed.