您好,因为涉及的类型,我在设置课程时遇到了一些困难。 这是想法:
A类有一个私有的arraylist,它应该被B类的实例填充。 因此,类A的任何实例都将具有类B类元素的ArrayList。 类A具有向其ArrayList添加B的新实例的功能。更具体地说,在A.Add中,实例化新B并初始化,然后添加到ArrayList。 B类是一个非常简单的类:它有一个枚举类型,应该还包含对外部对象/类或其他的引用。 假设有类* appleClass,peachClass,lemonClass *和classB是fruit类,而类A是fruitBasket。每当主代码看到一个水果时,它应该要求A级将其添加到篮子中。这意味着,A.add( thisfruit ),但这种水果可能是任何水果类。这反过来意味着我需要一个通用的签名来实例化classB,并将它添加到A.arraylist。我不知道我是否有任何意义,但我也会尝试提供一些代码来解释我的问题。
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);
}
}
我应该如何使用模板?我知道上面的代码是错误的,但我无法想象这是如何做得最好的。
谢谢
亚历
修改的 谢谢大家的答案。它们似乎都指向使用基类/抽象类Fruit,并从中获取特定的水果。我很遗憾地告诉你,我的实际项目不涉及水果,我只是为了简单而使用它们。实际项目是在 Unity 中,而“水果”的somr来自Unity类,其他一些“水果”是我自己的类。这意味着我无法为Unity的命名空间声明父类。我更希望能够对“水果”有一个通用的引用,这将成为旧C中的无效指针。我知道C#是强类型的,并且不会允许大多数类似指针的用法,但必须我可以将“未知”引用对象传递给类/函数并稍后使用/解析...
答案 0 :(得分: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);
}
}
可以通过运算符is了解从列表中获取的元素的确切类型:
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;
}
但是如果你需要这样做,那么也许你是从错误的角度来解决问题。
答案 1 :(得分:1)
C#没有模板,但确实有generics,这是一个类似的概念。你非常接近,但你的Fruit
类根本不需要是通用的。只需确保所有Lemon
,Apple
和Peach
类都继承自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() { }
}
现在,您可以使用generic constraint这样设计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);
答案 2 :(得分: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);
}
}
答案 3 :(得分:0)
再次感谢您的回答。我想出了一个方法,我只想描述一下,然后对它进行评论。我甚至不知道在C#中做我想的是否合法,我认为C ++允许这样做。 这里是: 我找到了一种创建抽象类的方法。在其中我有一个枚举,它存储每个实例的派生类的类型。所以所有“水果类”都将从父类派生,并在其构造函数中设置它们的类型。稍后我将把父实例添加到“Basket”中,并使用强制转换来解析实际的实例。
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”并确定父母的果实。 如果这样做(现在,或者稍作修改),它对我有用。