1

A sample code I tried to return an instance of class is given below.

public object getConstructorclass(int i)
{  
    if(i==1)
    {
       Type type = Type.GetType("test1");
    }else
    {
       Type type = Type.GetType("test2");
    }
    return Activator.CreateInstance(type); 
}    

var objcls = getConstructorclass(1);
objcls.callclass();//error occured

How can I mention the class type here since the type is not known at compile time but it will decided at runtime.In the above example i just pass a value 1 (it can be anything and that class will be called accordingly), and the class test1 called.

here I will get an error on the line objcls.callclass(), because objcls is an object instance that doesn't have a callclass()method.

How can I restructure this piece of code? My aim is if I mention a class in the getConstructorclass() method, an object should be returned so as to use it in the further code to invoke the members of that class.

3
  • 3
    Can I ask what you are trying accomplish through doing this? (Btw, from your example you know that the type is whatever test1 is) Commented Sep 4, 2014 at 10:06
  • Be careful of namespaces with the Activator. You should be ok doing the above, in general. However, you could provide a base class for the set of objects you wish to construct dynamically, then restrict the return type of the getConstructorClass() method to this base class so that it is a little more typesafe. Commented Sep 4, 2014 at 10:09
  • I cant assure always test1 will be called. The question updated which consists of a better view of my scenario. Commented Sep 4, 2014 at 10:48

5 Answers 5

2

If you know that your classes will have this method, you should use a common interface for them and implement it accordingly. Then you will work with classes that you have made sure it will work.

It would look like this

IMyInterface objcls = getconstrorclass() as IMyInterface;
if (objcls != null)
    objcls.callclass();
else
    // we failed miserably and should do something about it

I don't think you should use some generic object returning constructor based on an int variable, if your classes don't have anything in common. It's really weird to handle it like this and it may lead to various problems (some of which you're currently already experiencing). Generic class constructors make sense if the classes are somewhat related and you can predict the outcome, but to create a do-it-all method.. Not so sure about correctness of such approach.

Anyway, if you insist (not recommended, but as you wish), you can create some checks for a type like this:

var createdObject = getConstructorclass(1);
if (createdObject is MyClass1)
{
    var specificObject = (MyClass1)createdObject;
    specificObject.callMethod1(); 
}
else if (createdObject is MyClass2)
{
    var specificObject = (MyClass2)createdObject;
    specificObject.callSomeOtherMethod();
}
...

But it gets very error prone soon, refactoring will probably be a nightmare etc., but it's your call..

Or you maybe can use solution from pwas, but to me it seems unnecessarily complicated for such a basic task. Looks nice and all, but it still returns only the type "object", so it doesn't really solve your specific problem.

Also, to address one issue I'm not sure you understand - you've already created the instance, you just return type object. That is why you can't call any specific methods on this object, because first you have to cast it to something, that actually has that method and make sure the cast can be done (inheritance etc).

Sign up to request clarification or add additional context in comments.

12 Comments

You got there before me. :-)
i will have multiple classes and needs to invoke these classes dynamically. ie var objcls = getConstructorclass(1); ,objcls should contain the instance of the class that i dynamically invoked.
@user1648142, and your problem is? You can still use this solution, just adapt it to your needs...
can you elaborate your answer on how i can use a common interface for my requirement? in my case, I will have multiple classes and depends up on the version provided as input, the classes will be invoked. Also the classes may contain same functions with same signature so interface cannot be used i guess. correct me if im wrong.
@user1648142, it doesn't matter what class it will invoke as long as the target class has implemented that method. And that's when interface comes into play, because if your classes inherit from this interface, you have guaranteed that you can call that method. Your example code shows the same. You're instantiating more types of classes, but you still try to call that one method => use interface that contains it and make your classes implement the interface.
|
1

If interface solution (see other answers) is enough, don't look at this answer. When you can't use common base class / interface and you still want call members, you can use solution with is keyword (and check types). Instead of writing many ifs for each case, you can use fluent API:

object obj = this.getConstructorclass();
obj.StronglyInvoke()
   .When<int>(value => Console.WriteLine("Got {0} as int", value))
   .When<string>(value => Console.WriteLine("Got {0} as string", value))
   .OnFail(() => Debug.Write("No handle."))
   .Invoke();

Solution:

public class GenericCaller
{
    private IList<GenericInvoker> invokers = new List<GenericInvoker>();

    private readonly object target;

    private Action failAction;

    public GenericCaller(object target)
    {
        if (target == null)
        {
            throw new ArgumentNullException("target");
        }

        this.target = target;
    }

    public GenericCaller OnFail(Action fail)
    {
        this.failAction = fail;
        return this;
    }

    public GenericCaller When<T>(Action<T> then)
    {
        if (then == null)
        {
            throw new ArgumentNullException("then");
        }

        var invoker = new GenericInvoker<T>(this.target, then);

        this.invokers.Add(invoker);

        return this;
    }

    public void Invoke()
    {
        if (this.invokers.Any(invoker => invoker.Invoke()))
        {
            return;
        }

        if (this.failAction == null)
        {
            throw new InvalidOperationException("Handler not found");
        }

        this.failAction();
    }

    public abstract class GenericInvoker
    {
        protected readonly object target;

        protected GenericInvoker(object target)
        {
            this.target = target;
        }

        public abstract bool Invoke();
    }

    public class GenericInvoker<T> : GenericInvoker
    {
        private readonly Action<T> then;

        public GenericInvoker(object target, Action<T> then)
            : base(target)
        {
            this.then = then;
        }

        public override bool Invoke()
        {
            if (this.target.GetType() == typeof(T))
            {
                this.then((T)this.target);
                return true;
            }

            return false;
        }
    }
}

public static class Extensions
{
    public static GenericCaller StronglyInvoke(this object o)
    {
        return new GenericCaller(o);
    }
}

Remeber - it would be more elegant to use common interface (as other answers say) - my is only alternative way.

Comments

0

Declare your variable as dynamic

dynamic objcls = getconstrorclass();

Using this the will be determined at run-time, whatever the getconstrorclass method returns. You can access any member of the type and you won't get any error at compile-time. But if you try to access a member which doesn't exists you will get a RuntimeBinderException at runtime.

1 Comment

This technically does help OP, but it most likely doesn't solve the underlying problem. At least explain what dynamic does and what the pitfalls are of calling a method on a type that doesn't have that method.
0

I would recommend using an interface and restricting the classes that you can instantiate this way to only those that implement the interface.

public interface IMyInterface
{
    void callclass();
}

public <T> getConstructorClass()
{
    T instance;
    Type type = Type.GetType("test1");

    // instance will be null if the object cannot be cast to type T.
    instance = Activator.CreateInstance(type) as T;
    return T;
}

IMyInterface objcls = getConstructorClass<IMyInterface>();
if(null != objcls)
{
    objcls.callclass();
}

2 Comments

so How i can use reflection in the line IMyInterface objcls = getConstructorClass<IMyInterface>(); I cant mention IMyInterface here coz i will have multiple classes and i cant loop through the condition so depends up on the input i will create a class instance. IMyInterface should be define using reflection.
@user1648142 The answer below, from pwas uses templated generics, rather than explicit reflection. It looks like a nice solution, if you really, absolutely cannot use an interface.
-2

not sure what you want to achieve in the end, but this looks like a job for "Dependency Injection" - here is a nice sample using autofac

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.