我想创建一个可以容纳许多相同类型的类的类。例如,让我说我有一个基类如下:
public class BaseClass
{
public string MyBaseString
{
get;
set;
}
}
然后我有一些像这样的派生类:
public class DerivedClass : BaseClass
{
public MyDerivedClassString
{
get;
set;
}
}
public class DerivedClass2 : BaseClass
{
public MyDerivedClass2String
{
get;
set;
}
}
现在我想要一个接受其中一个实现的类,并使用它。这是我唯一能想到的,但必须有更好的方法:
public class ClassA
{
public object MyClass
{
get;
set;
}
public ClassA (object myClass)
{
MyClass = myClass;
if (object is BaseClass)
{
//do something
}
else if (object is DerivedClass)
{
//do something specific to derived class
}
else if (object is DerivedClass2)
{
//do something specific to derived class 2
}
}
}
澄清:我想要实现的具体目标是使用ClassA作为BaseClass的各种实现的容器类。我想要完成的业务目标是创建一个Legend对象,该对象可能使用多种颜色方案(即Mono Color Ramp,Multi Color Ramp等)。所以我希望Legend类包含正在使用的ColorScheme,但仍然可以访问该颜色方案的独特属性以便稍后进行修改。
澄清2 根据我得到的各种回复,我想我会提供我正在尝试做的完全复制:
public class BaseColorScheme
{
List<Color> _colors = new List<Color>();
public List<Color> Colors
{
get
{
return _colors;
}
set
{
_colors = value;
}
}
}
public class SingleColorScheme : BaseColorScheme
{
public Color MidColor
{
get;
set;
}
public SingleColorScheme( Color midColor, int numberOfClassifications )
{
Colors = CreateMonoColorRamp( midColor, numberOfClassifications );
}
}
public class MultiColorScheme : BaseColorScheme
{
public Color StartColor
{
get;
set;
}
public Color EndColor
{
get;
set;
}
public Color MidColor
{
get;
set;
}
public MultiColorScheme( Color startColor, Color endColor, Color midColor )
{
StartColor = startColor;
EndColor = endColor;
MidColor = midColor;
Colors = //do something to define multi color scheme
}
}
然后我会有一个类似
的传奇类public class Legend
{
public object ColorScheme
{ get; set; }
public Guid LegendId
{ get; set; }
public Legend(object colorScheme)
{
ColorScheme = colorScheme;
}
}
最后,我可能有一个位于图例顶部的表单,该表单根据颜色方案的类型显示各种颜色方案的属性。希望这有助于澄清一点。
答案 0 :(得分:5)
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA(T myClass) { MyClass = myClass; }
}
除此之外,将类层次结构的公共接口定义为接口或基类中的方法(具体,抽象或虚拟)。然后你可以放心,所有派生类都有这样的方法/属性,并且可以在你的通用包装器中使用它们。
答案 1 :(得分:3)
不要让ClassA执行任何需要完成的任务,您可以使用多态,让类自己完成。
只需在基类中声明一个虚方法,让它做你需要做的任何事情,然后在子类中重写这个方法。在ClassA中的方法中,您只需要在接收的对象上调用该方法作为参数 - 而无需关心特定类型。
答案 2 :(得分:0)
如果你需要根据哪个派生类来访问不同的属性,这样的东西会有所帮助:
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA(T myClass) { MyClass = myClass; }
public void DoStuffToMyClass()
{
if(MyClass is BaseClass)
{ // do base class stuff }
else if(Myclass is DerivedClass)
{ // do DerivedClass stuff }
else if(MyClass is DerivedClass2)
{ // do DerivedClass2 stuff }
}
}
这为您提供了类型安全性,以确保您至少拥有BaseClass对象,并且可能是派生类。
答案 3 :(得分:0)
答案是多态,让对象自己做。
public class BaseClass
{
public string MyString { get; set; }
public virtual string DoIt()
{
return "I'm Base Class";
}
}
public class DerivedClassA
{
public override string DoIt()
{
return "I'm Derived Class A";
}
}
public class DerivedClassB
{
public override string DoIt()
{
return "I'm Derived Class B";
}
}
....
public ClassA (BaseClass myClass)
{
MyClass = myClass;
MyClass.DoIt();
}
.....
ClassA x1 = ClassA(new BaseClass()) // calls BaseClass.DoIt()
ClassA x2 = ClassA(new DerivedClassA()) // calls DerivedClassA.DoIt()
ClassA x3 = ClassA(new DerivedClassB()) // calls DerivedClassB.DoIt()
每当你发现自己根据对象的运行时类型采取不同的行为时,你就会处理破坏OO原则的代码,即一个不尊重基类契约的类。
答案 4 :(得分:0)
您可以使用虚拟方法吗?
public abstract class BaseClass
{
public abstract void DoStuff();
}
public class DerivedClass1 : BaseClass
{
public override void DoStuff()
{
...
}
}
public class DerivedClass2 : BaseClass
{
public override void DoStuff()
{
...
}
}
没有泛型:
public class ClassA
{
public BaseClass MyClass
{
get;
set;
}
public ClassA (BaseClass myClass)
{
MyClass = myClass;
myClass.DoStuff();
}
}
或使用泛型:
public class ClassA<T> where T : BaseClass
{
public T MyClass { get; set; }
public ClassA (T myClass)
{
MyClass = myClass;
myClass.DoStuff();
}
}
答案 5 :(得分:0)
保持简单:多态
希望您的对象具有通用界面,例如:
class Base {
public virtual void DoSomething() { /* Default implementation */ }
}
class Derived1 : Base {
public override void DoSomething() { /* Implementation specific to this type */ }
}
class Derived2 : Base {
public override void DoSomething() { /* Another implementation specific to this type */ }
}
或者他们可能实现了一个通用接口。所以希望你的消费类可以尽可能保持输入的最一般表示并调用代码:
class Dependent {
public Dependent(Base instance) {
instance.DoSomething();
}
}
因此,您的Dependent类实际上并不是它是派生类型还是基类型。
不那么简单:访客模式
有时,多态性并不真正起作用,如果您需要访问派生类的特定成员,并且这些成员不在基类中,则尤其如此。访问者模式在这种情况下运行良好,特别是如果您有一个固定的,定义明确的对象图。
public interface IVisitor<T> {
T Visit(Base x);
T Visit(Derived1 x);
T Visit(Derived2 x);
}
class Base {
public virtual T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string BaseString { get; set; }
}
class Derived1 : Base {
public override T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string Derived1String { get; set; }
}
class Derived2 : Base {
public override T Accept<T>(IVisitor<T> visitor) { visitor.Visit(this); }
public string Derived2String { get; set; }
}
因此Derived1
和Derived2
具有不同的属性集,如果您需要在没有运行时类型检查的情况下访问这些属性,请实现访问者:
class DefaultStringVisitor : IBaseVisitor<string> {
public string Visit(Base x) { return x.BaseString; }
public string Visit(Derived1 x) { return x.Derived1String; }
public string Visit(Derived2 x) { return x.Derived2String; }
}
class Dependent {
public Dependent(Base x) {
string whatever = x.Accept<string>(new DefaultStringVisitor());
}
}
因此,访问者模式使您无需进行类型检查即可访问派生对象的成员。它有点不灵活(即需要知道前面要访问的对象),但它可能适合您的需要。