Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

Generics in C#

Posted on 2011-03-07
10
Medium Priority
?
354 Views
Last Modified: 2013-12-17
I am coming accross a very interesting problem.
I have the following classes defined as follows:
public class classA
{
        public int Type {get;set;}

        public MyCollection<T> MyCol {get;set;}

        //other properties and methods
}

public class TypeA
{
//class definition
}

public class TypeB
{
//class definition
}

public class TypeC
{
//class definition
}

the problem is that I want MyCollection<T> to hold either TypeA, TypeB or TypeC depending on the value in classA.Type when instantiating classA.

I found a way to build a generic collection that can hold any of the three class but the problem is tyhat when I am defining MyCol property for classA I have to pick a specific class (classA, classB or classC)

Any idea??


0
Comment
Question by:racineconde
  • 4
  • 3
  • 2
  • +1
10 Comments
 
LVL 23

Accepted Solution

by:
wdosanjos earned 1500 total points
ID: 35061890
I think generics won't help you here, because you are changing the type returned by public MyCollection<T> MyCol {get;set;} at run-time.

If TypeA, TypeB, and TypeC are similar classes with the same methods / properties, you could create an interface (for example, MyInterface) and have TypeA, TypeB, and TypeC implement it.  Then you could have public MyCollection<MyInterface> MyCol {get;set;}.  Otherwise, the only thing you can return is probably MyCollection<object>.
0
 
LVL 4

Expert Comment

by:rd707
ID: 35061975
My understanding is that generics allow you to write code that will accept any type. You still have to define that type at some point otherwise how can the compiler know how to compile it?

If the object have similarities, you'd probably be better off defining this in an interface and implementing it in your child objects (as wdosanjos mentions above).
0
 

Author Comment

by:racineconde
ID: 35062070
classA, classB and classC are completely different, but thanks for your input anyway.
0
Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

 
LVL 4

Expert Comment

by:rd707
ID: 35062151
You could still do it of course, at the expense of a meaningful object structure. Not really how generics are supposed to be used, but it could be done... * shudders *

0
 

Author Comment

by:racineconde
ID: 35067888
Is there then another way to achieve this without using generics?
0
 
LVL 4

Expert Comment

by:rd707
ID: 35068641
You can still use generics but implement each instance as type object. In the generic code though, you'd need to write code to handle each type.

Again, this would be slightly contradictory as to how generics are supposed to work.
0
 
LVL 7

Expert Comment

by:dimaj
ID: 35069858
Just use a collection of Object. When you need to access your items, do a test to see if current Object is an instance of TypeA TypeB or TypeC and cast it accordingly.

Also, you could have an empty base class (let's say MyTypes) and make each of your classes derive from MyTypes. Then, make your collection of type MyTypes.
0
 
LVL 4

Expert Comment

by:rd707
ID: 35070531
I'd just question why you're trying to shoehorn all these types into using the same code when all you're going to have to do is to write casts to pick them out anyway.

Unless this is just an academic exercise...
0
 
LVL 23

Expert Comment

by:wdosanjos
ID: 35070598
It depends on the intended use of these classes. Here is a possible approach (sample runs as a console app):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    public class ClassA
    {
        private int _type;
        public int Type
        {
            get { return _type; }

            set
            {
                _type = value;

                switch (_type)
                {
                    case 1: MyCol = new List<TypeA>(); break;
                    case 2: MyCol = new List<TypeB>(); break;
                    case 3: MyCol = new List<TypeC>(); break;
                    default: MyCol = null; break;
                }
            }
        }

        public IList MyCol { get; set; }

        public IList<TypeA> MyColA { get { return (MyCol as List<TypeA>); } }

        public IList<TypeB> MyColB { get { return (MyCol as List<TypeB>); } }

        public IList<TypeC> MyColC { get { return (MyCol as List<TypeC>); } }

        //other properties and methods
    }

    public class TypeA
    {
        //class definition
    }

    public class TypeB
    {
        //class definition
    }

    public class TypeC
    {
        //class definition
    }

    // Test class
    public class Program
    {
        public static void Main()
        {
            var a = new ClassA();

            a.Type = 1;// a.MyCol is now of List<TypeA>

            a.MyCol.Add(new TypeA());
            a.MyCol.Add(new TypeA());
            a.MyCol.Add(new TypeA());
            a.MyCol.Add(new TypeA());

            foreach (var n in a.MyCol)
            {
                Console.WriteLine(n);
            }

            Console.WriteLine(a.MyColA);
            Console.WriteLine(a.MyColB);    // return null, since a.MyCol is a List<TypeA>
            Console.WriteLine(a.MyColC);    // return null, since a.MyCol is a List<TypeA>

            try
            {
                a.MyCol.Add(new TypeB()); // this will throw an exception
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            a.Type = 2; // a.MyCol is now of List<TypeB>

            a.MyCol.Add(new TypeB()); // this will not throw an exception
            a.MyCol.Add(new TypeB());
            a.MyCol.Add(new TypeB());
            a.MyCol.Add(new TypeB());

            foreach (var n in a.MyCol)
            {
                Console.WriteLine(n);
            }

            Console.WriteLine(a.MyColA);    // return null, since a.MyCol is a List<TypeB>
            Console.WriteLine(a.MyColB);
            Console.WriteLine(a.MyColC);    // return null, since a.MyCol is a List<TypeB>

        }
    }
}

Open in new window

0
 

Author Closing Comment

by:racineconde
ID: 35231625
Take a guess!
0

Featured Post

Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

More often than not, we developers are confronted with a need: a need to make some kind of magic happen via code. Whether it is for a client, for the boss, or for our own personal projects, the need must be satisfied. Most of the time, the Framework…
This article shows how to deploy dynamic backgrounds to computers depending on the aspect ratio of display
Is your data getting by on basic protection measures? In today’s climate of debilitating malware and ransomware—like WannaCry—that may not be enough. You need to establish more than basics, like a recovery plan that protects both data and endpoints.…
Screencast - Getting to Know the Pipeline

886 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question