How to implement an abstract method with a generic class in C #

2

I'm creating a functional Factory where I define what kind of output it is and what the required implementation methods are.

With this implementation, when I try to use the object obj within the function that does every factory process of that object, it can not interpret it as being Bar type.

  

The idea is that I can have the same statement FooFactory.build() for multiple types, changing only the encapsulated implementation and always having a Foo as the return.

How to solve?

My code looks like this:

public abstract class Factory<T> where T : class {
    public abstract T Build<U>(U obj) where U : class;
}
public class Quadrado {
    public int Largura { get; set; }
    public int Altura { get; set;}
}
public class Retangulo {
    public int Largura { get; set; }
    public int Altura { get; set; }
}
public class QuadradoFactory: Factory<Quadrado> {
    public override Quadrado Build<Retangulo>(Retangulo o) => 
        new Quadrado() { Largura = o.Largura, Altura = o.Largura };
}
public class Program {
    public static void Main() {
        var f = new QuadradoFactory();
        var r = new Retangulo(){ Largura=2, Altura=4 };
        var q = f.Build<Retangulo>(r);

        System.Console.WriteLine(
            "Largura: " + q.Largura + 
            "Altura: " + q.Altura
        );
    }
}
    
asked by anonymous 29.08.2018 / 19:26

1 answer

4

Today it is not possible to specialize the generic type in the inherited method. This is called covariance. One obvious solution is to make the base type constrain to a type that exactly matches the Retangulo contract, which can even be generalized or even necessary.

Or you transfer genericity to type:

public abstract class Factory<T, U> where T : class  where U : class {
    public abstract T Build(U obj);
}
public class Quadrado {
    public int Largura { get; set; }
    public int Altura { get; set;}
}
public class Retangulo {
    public int Largura { get; set; }
    public int Altura { get; set; }
}
public class QuadradoFactory: Factory<Quadrado, Retangulo> {
    public override Quadrado Build(Retangulo o) => new Quadrado() { Largura = o.Largura, Altura = o.Altura };
}
public class Program {
    public static void Main() {
        var f = new QuadradoFactory();
        var r = new Retangulo(){ Largura = 2, Altura = 4 };
        var q = f.Build(r);
        System.Console.WriteLine("Largura: " + q.Largura + " Altura: " + q.Altura);
    }
}

See running on .NET Fiddle . And in Coding Ground . Also I placed GitHub for future reference .

The other solution is to throw away the type security (I prefer not):

public abstract class Factory<T> where T : class {
    public abstract T Build<U>(U obj) where U : class;
}
public class Quadrado {
    public int Largura { get; set; }
    public int Altura { get; set;}
}
public class Retangulo {
    public int Largura { get; set; }
    public int Altura { get; set; }
}
public class QuadradoFactory: Factory<Quadrado> {
    public override Quadrado Build<U>(U o) {
        var obj = o as Retangulo;
        if (obj == null) return null;
        return new Quadrado() { Largura = obj.Largura, Altura = obj.Altura };
    }
}
public class Program {
    public static void Main() {
        var f = new QuadradoFactory();
        var r = new Retangulo(){ Largura = 2, Altura = 4 };
        var q = f.Build<Retangulo>(r);
        System.Console.WriteLine("Largura: " + q.Largura + " Altura: " + q.Altura);
    }
}

See running on .NET Fiddle . And in Coding Ground . Also I placed GitHub for future reference .

    
29.08.2018 / 19:45