Return one of two possible objects of different types sharing a method
我有两个班:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Articles { private string name; public Articles(string name) { this.name = name; } public void Output() { Console.WriteLine("The class is:" + this.GetType()); Console.WriteLine("The name is:" + name); } } |
和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Questionnaire { private string name; public Questionnaire(string name) { this.name = name; } public void Output() { Console.WriteLine("The class is:" + this.GetType()); Console.WriteLine("The name is:" + name); } } |
我想写一个方法,它采用一个整数(1表示应该返回
此方法必须返回这两个类之一的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
我应该使用什么返回类型,这样就可以对结果调用
为什么没有一个定义了
1 2 3 | public abstract class BaseType { public abstract void Output(); } |
1 2 3 4 5 6 7 | public class Articles : BaseType { // Output method here } public class Questionaire : BaseType { // Output method here } |
然后你可以做:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
你也可以通过一个
1 2 3 4 5 6 7 8 9 10 11 | public interface IInterface { void Output(); } public class Articles : IInterface { // Output method here } public class Questionaire : IInterface { // Output method here } |
然后您必须修改choose方法以返回
注意:即使不能更改原始类,也可以在使用
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class ArticlesProxy : Articles, IInterface { public ArticlesProxy(string name) : base(name){} } public class QuestionaireProxy : Questionaire, IInterface { Questionaire inner; public QuestionaireProxy(string name) { inner = new Questionaire(name); } public void Output() { inner.Output();} } |
像这样的怎么样:
1 2 3 4 5 6 7 8 | public interface IHasOutput { void Output(); } public class Articles : IHasOutput public class Questionnaire : IHasOutput |
然后:
1 | public static IHasOutput Choose... |
当然,除了
1 2 | var entity = MyClass.Choose(1,"MyName"); entity.Output(); |
而返回的具体实现并不重要。您知道它实现了一个公共接口。
这里提供的答案很好,但有一件事我不喜欢,那就是参数
您可以利用这里的仿制药,即制作方法
1 2 3 4 5 6 7 8 | public static T Choose<T>(string name) // type constraint to ensure hierarchy. where T : BaseClass // BaseClass have common functionality of both class. { // Unfortunately you can't create instance with generic and pass arguments // to ctor. So you have to use Activator here. return (T)Activator.CreateInstance(typeof(T), new[] { name }); } |
用途:
1 2 | Articles article = ClassWithChooseMethod.Choose<Articles>("name"); Questionnaire questionnaire = ClassWithChooseMethod.Choose<Questionnaire>("name2"); |
演示
编辑
正如注释
1 2 3 4 | enum ArticleType { Articles = 1, Questionnaire = 2 } |
并有EDOCX1[16]过载:
1 2 3 4 5 6 7 8 9 10 | public static BaseClass Choose(ArticleType type, string name) { switch (type) { case ArticleType.Articles: return ClassWithChooseMethod.Choose<Articles>(name); case ArticleType.Questionnaire: return ClassWithChooseMethod.Choose<Questionnaire>(name); default: return default(BaseClass); } } |
用途:
1 | var obj = ClassWithChooseMethod.Choose((ArticleType)userInput,"some name"); |
这使您有可能保持代码的整洁,并对将来的维护有用(例如,您可以在
另外,您可能有兴趣了解更多关于工厂模式的信息。
除非它们共享同一个基类或接口,否则您会非常困惑于
解决这个问题最灵活的方法是编写一个接口以及一个实现它的抽象基类。这样,如果基类在非常特殊的情况下不能满足您的需要,或者如果某个类已经从另一个类派生,您就可以自由地从基类派生类或直接实现接口。还可以使方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | public interface IHasOutput { void Output(); } public abstract class OutputBase : IHasOutput { protected string _name; public OutputBase(string name) { _name = name; } #region IHasOutput Members public virtual void Output() { Console.WriteLine("The class is:" + this.GetType()); Console.WriteLine("The name is:" + _name); } #endregion public static IHasOutput Choose(int x, string name) { switch (x) { case 1: return new Articles(name); case 2: return new Questionnaire(name); default: return null; } } } public class Articles : OutputBase { public Articles(string name) : base(name) { } } public class Questionnaire : OutputBase { public Questionnaire(string name) : base(name) { } } |
更新
解决这个问题的另一个非常简单的方法是覆盖
1 2 3 4 5 6 7 | public override string ToString() { return String.Format("The class is: {0} The name is: {1}", this.GetType(), _name); } |
你可以这样称呼它:
1 2 | object obj = Factory.Choose(1,"Test"); Console.WriteLine(obj); |
不需要接口和基类!准确地说,基类是
您有三个选择:
1)使调查问卷和项目从同一个基类继承,并使该基类的类型成为方法的返回类型。
2)生成返回类型对象。
3)使您的返回类型具有动态性。