Home > OS >  using class objects as a <T> in methods
using class objects as a <T> in methods

Time:02-03

It's a training case. I have several classes with some similar properties - X and Y as coordinates for example. And I want to create a special class < T > with a function which have to change X and Y at the objects of this classes. I want to pass objects of this classes as < T > but the problem is that function doesn't know about X and Y at the object they accepted as a parameters.

namespace testing_Templates
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var temp = new Car();
            var template = new TemplateTest<Car>();
            Console.WriteLine(temp);
            template.Move(temp, "Up", 20);  // want to change Y of temp object of Car class
            Console.WriteLine(temp);
        }

        
        // Special <T> class with function, changing X and Y in different class objects
        class TemplateTest<T> where T: class
        {
            public int X { get; set; }
            public int Y { get; set; }

            public void Move(T obj, string direction, int steps)
            {
                TemplateTest<T> tempobj;
                tempobj = (TemplateTest<T>) obj;            //ERROR
                Console.WriteLine(tempobj.Equals(obj));
                switch (direction)
                {
                    case "Up"    : 
                        {
                            this.Y  = steps;
                            Console.WriteLine(tempobj.Equals(obj));
                            break; 
                        }
                    case "Down":
                        {
                            this.Y -= steps;
                            break;
                        }
                    case "Left":
                        {
                            this.X -= steps;
                            break;
                        }
                    case "Right":
                        {
                            this.X  = steps;
                            break;
                        }
                    default:
                        break;
                }
            }
        }

        
        // Test class with X and Y
        class Car
        {
            int year;
            string name;
            int speed;
            int x;
            int y;

            public Car()
            {
                year = 1974;
                name = "Zhiguli";
                speed = 60;
                x = 20;
                y = 0;
            }

            public Car(int year, string name, int speed)
            {
                this.year = year;
                this.name = name;
                this.speed = speed;
                x = -20;
                y = -10;
            }

            public int Year { get => year; set => year = value; }
            public string Name { get => name; set => name = value; }
            public int Speed { get => speed; set => speed = value; }
            public int X { get => x; set => x = value; }
            public int Y { get => y; set => y = value; }

            public override string ToString()
            {
                return $"Car {Name} ({Year}) with speed {Speed} is on point {X},{Y}";
            }
        }

    }
}

Is it possible to use class object as T in such tasks? If it's possible then what's wrong?

CodePudding user response:

In your case, you need to use interface

Create interface ITemplateObj

public interface ITemplateObj
{
    public int X { get; set; }
    public int Y { get; set; }
}

implement in type Car

class Car : ITemplateObj

then update the handler

class TemplateTest<T> where T : ITemplateObj
{
    public void Move(T obj, string direction, int steps)
    {
        var tempobj = obj;
        Console.WriteLine(tempobj.Equals(obj));
        switch (direction)
        {
            case "Up":
                {
                    obj.Y  = steps;
                    Console.WriteLine(tempobj.Equals(obj));
                    break;
                }
            case "Down":
                {
                    obj.Y -= steps;
                    break;
                }
            case "Left":
                {
                    obj.X -= steps;
                    break;
                }
            case "Right":
                {
                    obj.X  = steps;
                    break;
                }
            default:
                break;
        }
    }
}

full code like this:

void Main(string[] args)
{
    var temp = new Car();
    var template = new TemplateTest<Car>();
    Console.WriteLine(temp);
    template.Move(temp, "Up", 20);  // want to change Y of temp object of Car class
    Console.WriteLine(temp);
}

public interface ITemplateObj
{
    public int X { get; set; }
    public int Y { get; set; }
}

// Special <T> class with function, changing X and Y in diffirent class objects
class TemplateTest<T> where T : ITemplateObj
{
    public void Move(T obj, string direction, int steps)
    {
        var tempobj = obj;
        Console.WriteLine(tempobj.Equals(obj));
        switch (direction)
        {
            case "Up":
                {
                    obj.Y  = steps;
                    Console.WriteLine(tempobj.Equals(obj));
                    break;
                }
            case "Down":
                {
                    obj.Y -= steps;
                    break;
                }
            case "Left":
                {
                    obj.X -= steps;
                    break;
                }
            case "Right":
                {
                    obj.X  = steps;
                    break;
                }
            default:
                break;
        }
    }
}


// Test class with X and Y
class Car : ITemplateObj
{
    int year;
    string name;
    int speed;
    int x;
    int y;

    public Car()
    {
        year = 1974;
        name = "Zhiguli";
        speed = 60;
        x = 20;
        y = 0;
    }

    public Car(int year, string name, int speed)
    {
        this.year = year;
        this.name = name;
        this.speed = speed;
        x = -20;
        y = -10;
    }

    public int Year { get => year; set => year = value; }
    public string Name { get => name; set => name = value; }
    public int Speed { get => speed; set => speed = value; }
    public int X { get => x; set => x = value; }
    public int Y { get => y; set => y = value; }

    public override string ToString()
    {
        return $"Car {Name} ({Year}) with speed {Speed} is on point {X},{Y}";
    }
}

CodePudding user response:

Your example does not make all to much sense, but I suspect you want a generic constraint. This lets you use a generic object, as long as it fulfills some interface. For example:

public interface IPosition{
    int X {get;set;}
    int Y {get;set;}
}
class TemplateTest<T> where T: IPosition
     public void Move(T obj, string direction, int steps){
         // This works, since we have promised that all T
         // have a X-property of type int
          obj.X  = steps;
     }
}

However, in some cases generics is the wrong approach, and you should just replace the T with your IPosition. One possible advantage of generics is that it will compile multiple versions of the method, one for each T, and that may enable some optimizations. But this is only relevant in very specialized cases.

  • Related