如何接受通用类并使用其属性/方法

时间:2010-06-09 20:50:47

标签: c# .net

我想创建一个可以容纳许多相同类型的类的类。例如,让我说我有一个基类如下:

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;
     }
}

最后,我可能有一个位于图例顶部的表单,该表单根据颜色方案的类型显示各种颜色方案的属性。希望这有助于澄清一点。

6 个答案:

答案 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; }
}

因此Derived1Derived2具有不同的属性集,如果您需要在没有运行时类型检查的情况下访问这些属性,请实现访问者:

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());
    }
}

因此,访问者模式使您无需进行类型检查即可访问派生对象的成员。它有点不灵活(即需要知道前面要访问的对象),但它可能适合您的需要。