2014-02-08 2 views
0

Здравствуйте, у меня возникли трудности с настройкой класса из-за соответствующих типов. Вот идея:Функции и типы шаблонов в C#

класс А имеет частный ArrayList, который, как предполагается, должны быть заполнены с экземплярами класса В. Таким образом, любой экземпляр класса А будет иметь на ArrayList элементов класса B. класс A имеет функцию, которая добавляет в свой ArrayList новый экземпляр B. Чтобы быть более конкретным, внутри A.Add создается новый B и инициализируется, а затем добавляется в ArrayList. класс B - очень простой класс: он содержит один enum Введите его, и он должен также содержать ссылку на внешний объект/класс или что-то еще. Предположим, что есть классы * appleClass, peachClass, lemonClass * и classB - класс фруктов, а класс A - это плод. Каждый раз, когда основной код видит фрукты, он должен попросить класс А добавить его в корзину. это означает, что A.add (thisfruit), но этот фрукт может быть любым фруктовым классом. что в свою очередь означает, что мне нужна общая подпись для создания экземпляра класса B и добавление его в 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); 
    } 
} 

SomeКак использовать шаблоны ?? Я знаю, что код выше неправильный, но я не могу понять, как это лучше всего сделать.

Спасибо

Alex

EDIT Спасибо всем за ответы. Все они, похоже, указывают на использование базового/абстрактного класса Fruit и получают от него определенные плоды. Мне жаль говорить вам, что мой актуарийный проект не связан с фруктами, я просто использовал их для простоты. Фактический проект находится в Unity и somr из «фруктов» поступают из классов Unity, некоторые другие «Фрукты» - это мои собственные классы. это означает, что я не могу объявить родительский класс для тех, которые приходят из пространства имен Unity. Я больше надеялся, что у меня будет общая ссылка на «плод», это будет пустой указатель на старый добрый C. Я знаю, что C# строго типизирован и не позволит использовать большинство указателей, но должен мне путь, чтобы пройти «неизвестное» ссылка-объект для класса/функции и использования/разрешить его позже ...

ответ

3

EDIT, чтобы отразить новую информацию в вашем вопросе: 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 в одной из своих реализаций (остерегайтесь, результат будет нулевым, если преобразование не представляется возможным, то есть вы использовали неправильные типы):

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

Но если вам нужно сделать это, то, возможно, вы приближаетесь к проблеме с неправильной точки зрения.

+0

Thank you @BlackBear для ответа. Другое дело: если я использую этот способ, вы предлагаете, когда я вернусь из списка A (в моем основном коде), мне нужно знать точный тип (плод), который есть у каждого элемента. Это будет возможно? Я не хочу просто знать, что это тип «Фрукты». Я хочу, чтобы топ знал, что это лимон или яблоко. пример: Список a = Basket.GetFruits(); переключатель (a [0] .c) { case 0: { Lemon L = a [0] .f; // заполнять это будет нормально ??? будет ли тип лимона? } // .... – Sagi2313

+0

@ Sagi2313 уверен, см. Мое редактирование – BlackBear

+0

@ Sagi2313 это заняло у меня некоторое время, но вы все равно можете делать то, что хотите, и не слишком много головных болей. См. Мое редактирование, пожалуйста, – BlackBear

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

Теперь вы можете создать свой Basket класс с generic constraint, как это:

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); 
0

В C# они называются методы Generic не Template Methods, поскольку они не генерируются для каждого времени во время компиляции.

Что касается вашего примера:

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); 
    } 
} 
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» и решить, что плод, который родитель. Если это работает (как сейчас, или с незначительными изменениями), это работает для меня.

Смежные вопросы