Solved

Generics in C#

Posted on 2011-03-07
10
339 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 500 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
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 
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

Resolve Critical IT Incidents Fast

If your data, services or processes become compromised, your organization can suffer damage in just minutes and how fast you communicate during a major IT incident is everything. Learn how to immediately identify incidents & best practices to resolve them quickly and effectively.

Question has a verified solution.

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

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
For those of you who don't follow the news, or just happen to live under rocks, Microsoft Research released a beta SDK (http://www.microsoft.com/en-us/download/details.aspx?id=27876) for the Xbox 360 Kinect. If you don't know what a Kinect is (http:…
This video shows how to quickly and easily add an email signature for all users on Exchange 2016. The resulting signature is applied on a server level by Exchange Online. The email signature template has been downloaded from: www.mail-signatures…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

860 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