4

I am newbie in C#. I am trying to create a Generic class. I have three classes and a Main/Generic class.

Three Classes

public class A
{
    public string Name { get; set; }
    public string Address { get; set; }

    public A(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }        
}

public class B
{
    public string Name { get; set; }
    public string Address { get; set; }

    public B(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }
}

public class C
{
    public string Name { get; set; }
    public string Address { get; set; }

    public C(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }
}

Generic Class

public class GenericClass<T>
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public T DynamicObject { get; set; }

}

I have successfully created a Generic class.

class Program
{
    static void Main(string[] args)
    {
        A objA = new A("Mohit", "India");
        GenericClass<A> objGenericClass = new GenericClass<A>(objA);

        Console.ReadLine();
    }

}

Now, if I need to use Class A/B/C property in the Generic class. How can I use it? I know that class reference type decide on the runtime. So, I can't use it in below way.But, Is there any other way?

public class GenericClass<T>
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public T DynamicObject { get; set; }


    public void UseClassPro()
    {
        Console.WriteLine("Address " + DynamicObject.Address);//Compile time error here.
    }

}
nozzleman
  • 9,529
  • 4
  • 37
  • 58
KiddoDeveloper
  • 568
  • 2
  • 11
  • 34

5 Answers5

6

The Other Answers are right, but...

I just want to point out: while those other answers promote valid C# code, they make the generic aspect of you implementation superflous. You don't need generics anymore:

Given a base class or interface like

public interface IHasAddress
{
    string Address { get; }
}

you don't need a Generic class anymore for what you are trying to achive (from what i can tell by the code you provided):

public class NotSoGenericClass
{
    public GenericClass(IHasAddress obj)
    {
        DynamicObject = obj;
    }

    public IHasAddress DynamicObject { get; set; }    
}

So as you can see, you can easily implement the desired behaviour w/o generics.

For you as a Beginner, i'd recommend the following basic rules when it comes to generics:

  1. When you think you have to use generics, force yourself to consider abstraction via interfaces, abstract classes or base classes first. This often leads to simpler and cleaner solutions.
  2. Same goes with Reflection. When you think you need Reflection, consider generics (Rule 1 is valid at that point to)

But Nothings wrong with Generics, its just more complex and often not needed. Compare the class above with the generic solution:

public class GenericClass<T> where T : IHasAddress  // just for the sake of generics
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public T DynamicObject { get; set; }    
}

Looks more complex and doesn't add any benefit, does it? Also note that you need a Interface/baseclass no matter what. Otherwise, you could also use Reflection (not recommended).

To actually answer your question

The precise answer to your question is:

You have to define that you generic parameter has to be assignable to IHasAddress using

public class GenericClass<T> where T : IHasAddress
                             ^^^^^^^^^^^^^^^^^^^^^
                                  This Part

This way, the compiler knows that T inherits or is of type IHasAddress or what ever you define. You can also pass multiple types at this place which adds mor flexibility when it comes to designing your interfaces.

Maybe, there are points to consider in your usecase which are not obvious from the information you provided in the question. In that case, feel free to add some details and i'll be happy to deep dive into those as well.

nozzleman
  • 9,529
  • 4
  • 37
  • 58
5

define interface:

public interface IABC
{
    string Name { get; set; }
    string Address { get; set; }
}

and in your generic class definition specify this interface:

public class GenericClass<T> where T: IABC
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public IABC DynamicObject { get; set; }    
}

All your 3 classes implemet this interface:

public class A : IABC
public class B : IABC
public class C : IABC

After that you could call properties of IABC

A objA = new A("Mohit", "India");
GenericClass<A> objGenericClass = new GenericClass<A>(objA);
var adress = objGenericClass.DynamicObject.Address;
Maksim Simkin
  • 9,561
  • 4
  • 36
  • 49
1

If you have properties in your generic arguments that share type and name, use a base class:

public class Base
{
    public string Address { get; set; }

    public A(string _address)
    {
        Address = _address;
    }        
}

public class A : Base
{
    public string Name { get; set; }

    public A(string _name, string _address) : base(_address)
    {
        Name = _name;
    }        
}

public class B : Base
{
    public string Name { get; set; }

    public B(string _name, string _address) : base(_address)
    {
        Name = _name;
    }        
}

public class C : Base
{
    public string Name { get; set; }

    public C(string _name, string _address) : base(_address)
    {
        Name = _name;
    }        
}

You can then use the base class as a constraint to your generic class:

public class GenericClass<T> where T : Base
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public T DynamicObject { get; set; }


    public void UseClassPro()
    {
        Console.WriteLine("Address " + DynamicObject.Address);//Compiles now
    } 
}

If you can not use a base class, use an interface:

public interface IBase
{
    string Address { get; set; }
}

public class A : IBase
{
    public string Name { get; set; }
    public string Address { get; set; }

    public A(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }        
}

public class B : IBase
{
    public string Name { get; set; }
    public string Address { get; set; }

    public B(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }
}

public class C : IBase
{
    public string Name { get; set; }
    public string Address { get; set; }

    public C(string _name, string _address)
    {
        Name = _name;
        Address = _address;
    }
}

public class GenericClass<T> where T : IBase
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public T DynamicObject { get; set; }


    public void UseClassPro()
    {
        Console.WriteLine("Address " + DynamicObject.Address);//Compiles now
    }
}
Sefe
  • 13,731
  • 5
  • 42
  • 55
0

Add an interface that implements the similar properties like the following :

public interface IInfo
{
    public string Name { get; set; }
    public string Address { get; set; }
}

public class GenericClass<T> where T : IInfo
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }

    public T DynamicObject { get; set; }


    public void UseClassPro()
    {
        Console.WriteLine("Address " + DynamicObject.Address);
    }

}
Ali Ezzat Odeh
  • 2,093
  • 1
  • 17
  • 17
0

There is no 'clean' way of getting a property from a generic class without inheritance, either through an interface or a base class, as shown in the other answers.

If you don't want to use inheritance, you can use reflection, although this is far less efficient than using an inherited class.

// the generic class
public class GenericClass<T> where T: IABC
{
    public GenericClass(T obj)
    {
        DynamicObject = obj;
    }
    public IABC DynamicObject { get; set; }    

    public T GetPropertyValue<T>(string propertyName)
    {
        var obj = GetType().GetProperty(propertyName).GetValue(this);
        return (T)Convert.ChangeType(obj, typeof(T))
    }
}

A objA = new A("Mohit", "India");
GenericClass<A> objGenericClass = new GenericClass<A>(objA);
var address = objGenericClass.GetPropertyValue<string>("address");

I stress that this is an alternative to inheritance that will not be very fast, but it might suit your needs.

martijn
  • 1,417
  • 1
  • 16
  • 26