给出了我试图返回类实例的示例代码。
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
我怎么能在这里提到类类型,因为该类型在编译时是未知的,但它会在运行时决定。在上面的例子中,我只传递一个值 1(它可以是任何东西,并且该类将被相应地调用(,然后调用类 test1。
在这里,我将在第 objcls.callclass()
行上收到错误,因为objcls
是一个没有callclass()
方法的object
实例。
如何重构这段代码?我的目标是如果我在 getConstructorclass()
方法中提到一个类,应该返回一个对象,以便在进一步的代码中使用它来调用该类的成员。
如果你知道你的类将有这个方法,你应该为它们使用一个通用接口并相应地实现它。然后,您将使用已确保它正常工作的类。
它看起来像这样
IMyInterface objcls = getconstrorclass() as IMyInterface;
if (objcls != null)
objcls.callclass();
else
// we failed miserably and should do something about it
我认为如果你的类没有任何共同点,你不应该使用一些基于 int 变量的通用对象返回构造函数。像这样处理它真的很奇怪,它可能会导致各种问题(其中一些您目前已经遇到(。如果类在某种程度上相关,并且您可以预测结果,但要创建一个全能方法,则泛型类构造函数是有意义的。不太确定这种方法的正确性。
无论如何,如果您坚持(不推荐,但如您所愿(,您可以为如下所示的类型创建一些检查:
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();
}
...
但它很快就会变得非常容易出错,重构可能会是一场噩梦等,但这是你的决定。
或者你可以使用pwas的解决方案,但对我来说,对于这样一个基本任务来说,这似乎不必要地复杂。看起来不错,但它仍然只返回类型"object",因此它并不能真正解决您的特定问题。
另外,为了解决一个问题,我不确定您是否理解 - 您已经创建了实例,您只需返回类型对象。这就是为什么你不能在这个对象上调用任何特定的方法,因为首先你必须把它强制转换为实际上具有该方法的东西,并确保可以完成强制转换(继承等(。
如果interface
解决方案(见其他答案(就足够了,不要看这个答案。当您无法使用公共基类/接口并且仍然需要调用成员时,您可以使用带有is
关键字(和检查类型(的解决方案。您可以使用流畅的 API,而不是为每个情况编写许多 if:
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();
溶液:
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 - 使用通用界面会更优雅(如其他答案所说( - 我的只是替代方法。
将变量声明为动态
变量dynamic objcls = getconstrorclass();
使用它,将在运行时确定,无论getconstrorclass
方法返回什么。您可以访问该类型的任何成员,并且在编译时不会收到任何错误。但是,如果您尝试访问不存在的成员,您将在运行时获得RuntimeBinderException
。
我建议使用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();
}
你最终想要实现什么,但这看起来像是"依赖注入"的工作 - 这是一个使用 autofac 的不错示例