0

Hello I am having some difficulty with setting up a class , because of the types involved. Here is the Idea:

class A has a private arraylist which is supposed to be filled with instances of class B. So any instance of class A will have its on ArrayList of class B elements. class A has a function to add to its ArrayList a new instance of B. To be more specific, inside the A.Add, a new B is instantiated, and initialized, then added to the ArrayList. class B is a very simple class: It has one enum Type in it, and it should also contain a reference to an external object/class or whatever. Suppose there are classes * appleClass, peachClass , lemonClass * and classB is the fruit class, and class A is the fruitBasket. The everytime the main code sees a fruit, it should ask class A to add it in the basket. that means, A.add(thisfruit), but this fruit might be any of the fruitclasses. which in turn means that I need a generic signature to instantiate classB , and add it to A.arraylist. I don;t know if I make any sense but I will also try to give some code to explain my problem.

class Lemon
{
    //....
}
class Apple
{
    //....
}
class Peach
{
    //....
}

class Fruit
{
    public int color;
    <T> fruit;///this should be the <T> type depending on the fruit class i am adding
    public Fruit(T f, int c){fruit = f; color = c;}
}

class Basket
{
    ArrayList FruitArray= new ArrayList();
    public void AddFruit<T>(T f,int c )
    {
        fru = new Fruit(f,c);
        FruitArray.Add(fru);
    }
}

SomeHow I should use templates?? I know the code above is wrong, but I can't figure how is this best done.

Thank You

Alex

EDIT Thank You all for your answers. They all seem to point to using a base/abstract class Fruit, and derive specific fruits from it. I am sorry to tell you that my actuall project doesn't involve fruits, I just used them for simplicity. The actual project is in Unity and somr of the "fruits" are coming from Unity classes , some other "Fruits" are my own classes. this means that I can't declare parent class for the ones that come from Unity's namespace. I was more hopeing to be able to have a generic reference to the "fruit" , that would be a void pointer in good old C. I know C# is strongly typed, and won't allow most pointer-like uses, but there must me a way to pass an "unknown" reference-to-object to a class/function and use/resolve it later...

4

4 回答 4

3

编辑以反映您问题中的新信息: ArrayList 是一种很好的方法,但在这种情况下我不会使用泛型,因为它会引起很多麻烦和代码重复。相反,我会使用反射在运行时查找并调用正确的重载。一段代码相当于一千字,所以这里有一个简单的控制台应用程序来展示这一点:

class ObjectA {
    public int A { get; set; }
    public ObjectA( int a ) {
        this.A = a;
    }
}

class ObjectB {
    public int B { get; set; }
    public ObjectB( int b ) {
        this.B = b;
    }
}

class ObjectC {
    public int C { get; set; }
    public ObjectC( int c ) {
        this.C = c;
    }
}

class DynamicOverloadResolution {
    ArrayList items;

    public DynamicOverloadResolution( ) {
        items = new ArrayList( ) { 
            new ObjectA( 1 ), new ObjectB( 2 ), new ObjectC( 3 )
        };
    }

    public void ProcessObjects( ) {
        foreach ( object o in items )
            processObject( o );
    }

    private void processObject( object o ) {
        Type t = typeof( DynamicOverloadResolution );
        IEnumerable<MethodInfo> processMethods = t.GetMethods( )
            .Where( m => m.Name == "process" );

        foreach(MethodInfo info in processMethods) {
            if ( info.GetParameters( ).First( ).ParameterType == o.GetType( ) )
                info.Invoke( this, new object[ ] { o } );
        }
    }

    public void process( ObjectA a ) { Console.WriteLine( a.A ); }
    public void process( ObjectB b ) { Console.WriteLine( b.B ); }
    public void process( ObjectC c ) { Console.WriteLine( c.C ); }
}

class Program {
    static void Main( string[ ] args ) {
        var d = new DynamicOverloadResolution( );
        d.ProcessObjects( );
    }
}

这是输出:

1
2
3

老答案:

您可以简单地使水果成为抽象类或接口,让所有东西都继承/实现它并保留水果列表:

interface IFruit {
    public int c { get; set; }
}

class Apple : IFruit { }
class Peach : IFruit { }
class Lemon : IFruit { }

class Basket {
    List<IFruit> fruitList = new List<IFruit>();

    public void AddIFruit<T>(int c) 
        where T : IFruit, new {

        var f = new T();
        f.c = c;
        fruitList.Add(f);
    }
}

使用运算符可以知道您从列表中取出的元素的确切类型

var f = fruitList.First();
if(f is Apple) { }
else if(f is Peach) { }
else if(f is Lemon) { }

或者,您可以使用as运算符将 IFruit 转换为其实现之一(请注意,如果无法进行转换,即您使用了错误的类型,则结果将为 null):

List<Fruit>a=Basket.GetFruits();
switch(a[0].c) { 
    case 0:
        Lemon L = a[0] as Lemon;
}

但是,如果您需要这样做,那么您可能是从错误的角度来处理问题。

于 2014-02-08T13:39:01.070 回答
1

C# 没有模板,但有泛型,这是一个类似的概念。你非常接近,但你的Fruit课程根本不需要是通用的。只需确保您的所有Lemon,ApplePeach类都继承自Fruit

class Fruit
{
    public int color;
    public Fruit() { } // default constructor for generic constrain below
}
class Lemon : Fruit
{
    //....
    public Lemon() : base() { } 
}
class Apple : Fruit
{
    //....
    public Apple() : base() { } 
}
class Peach : Fruit
{
    //....
    public Peach() : base() { } 
}

现在您可以使用这样的通用约束Basket来设计您的类:

class Basket
{
    List<Fruit> FruitList = new List<Fruit>();

    public void AddFruit<T>(int c) where T : Fruit, new()
    {
        fru = new T();
        fru.color = c;
        FruitList.Add(fru);
    }
}

Basket basket = new Basket();
basket.Add<Apple>(2);
于 2014-02-08T13:40:04.027 回答
0

在 C# 中,它们被称为通用方法而不是模板方法,因为它们不是在每次编译时生成的。

至于你的例子:

class Lemon : Fruit
{
    public Lemon(int c = 0) : base(c){}
    //....
}
class Apple : Fruit
{
    public Apple (int c = 0) : base(c){}
    //....
}
class Peach : Fruit
{
    public Peach (int c = 0) : base(c){}
    //....
}

class Fruit
{
    public int color;
    public Fruit(int c){ color = c; }
}

class Basket
{
    List<Fruit> fruits = new List<Fruit>();

    public void AddFruit(Fruit f)
    {
        fruits.Add(f);
    }

    public void CreateFruit<T>(int c) : where T : Fruit
    {
        Fruit f = Activator.CreateInstance<T>() as Fruit;
        f.color = c;
        fruits.Add(f);
    }
}
于 2014-02-08T13:45:12.477 回答
0

再次感谢您的回答。我只是想出了一个方法,我只是想描述它,并得到你的评论。我什至不知道在 C# 中做我认为的事情是否合法,我认为 C++ 允许这样做。就是这样:我找到了一种创建抽象类的方法。在其中我有一个枚举,它存储每个实例的派生类的类型。所以所有“水果类”都将从父类派生,并在其构造函数中设置它们的类型。稍后我会将父实例添加到“篮子”,并使用强制转换来解析实际实例。

class abstract parent
{
    public enum fruitType{lemon,apple,microsoft};
    public fruitType myType;
    public int ID;
}

class Lemon : parent
{
   Lemon(int i){ID=i;myType=fruitType.lemon};
   // various Lemon functions
}
class Apple: parent
{
   Apple(int i){ID=i;myType=fruitType.apple};
   // various Apple functions
}

then comes the Array:
class Basket
{
   public List<parent> basket=new List<parent>();
   void AddToBasket(parent p)
   {
    basket.Add(p);
   }

}
And in main:

class pgm
{
   void main()
   {
    Basket bsk=new Basket();
    parent pnt=new parent();
    Lemon  lmn=new Lemon();
    bsk.AddToBasket(lmn);// is this OK?

   }
}

当我需要读回篮子的内容时,我会以父级的身份读取它,检查“myType”并确定该父级是什么水果。如果这有效(就像现在一样,或者有微小的变化)它对我有用。

于 2014-02-08T15:23:38.530 回答