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

Asked

Viewed 150 times

4

I am creating a functional Factory where I define what is its output type and what are the required implementation methods.

With this implementation, when I try to use the object obj within the function that makes the whole Factory process of that object, he cannot interpret it as being of the Bar type.

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

How to solve?

My code is getting 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
        );
    }
}

1 answer

4


Today it is not possible to specialize the generic type in the inherited method. This is called covariance. An obvious solution is to make the base type restrict to a type that exactly meets the contract of Retangulo, which may even be generic or necessary.

Or you transfer the genre to the 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);
    }
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

The other solution is to throw away 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);
    }
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

  • No, in the model you showed you pass a string. doing so he really understood but if I use a compound class it does not work.

  • 1

    Class is class, there is no class that is composed or not composed. What you asked I answered, if the real problem is another is not in the question. I can’t answer because the question doesn’t show it.

  • OK, I rephrased the question

  • 1

    But I already answered what was asked. Now I don’t know if I have the answer, if I have time to see it. Now you’re asking another question.

  • 1

    I changed the answer, but don’t do this, it complicates for who answered.

  • I don’t think I expressed myself right the first time. really what I need is the second option since I can have multiple Build methods, based only on the type of information passed.

  • Then I think it’s better to think of something else, leave the code without robustness, with cognitive load to deal with. If I understand correctly. If it is something else, nor rolls, it will not work. Clearly this is not the real problem, but the solution should not even be this for the real problem.

Show 2 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.