0

Given the current structure of generic classes.

public abstract class Foo<TFoo, TBar>
    where TFoo : Foo<TFoo, TBar>
    where TBar : Bar<TFoo, TBar>
{
}

public abstract class Foo<TFoo> : Foo<TFoo, BarImpl>
    where TFoo : Foo<TFoo>
{
}

public class FooImpl : Foo<FooImpl>
{
}

public abstract class Bar<TFoo, TBar>
    where TFoo : Foo<TFoo, TBar>
    where TBar : Bar<TFoo, TBar>
{
}

public abstract class Bar<TFoo> : Bar<TFoo, BarImpl>
    where TFoo : Foo<TFoo>
{
}

public class BarImpl : Bar<FooImpl>
{
}

What I want is to set a default Bar on each implementation of Foo<TFoo>. At some other part in the code an instance of TBar is created which fails in case it is Bar<TFoo> as this is an abstract class.

However, the following error is thrown and I don't get the point what I can do or if this even possible at all.

The type 'BarImpl' must be convertible to 'Bar' in order to use it as parameter 'TBar' in the generic class 'Foo'

I already tried to let BarImpl derive from Bar<FooImpl, BarImpl> which had no effect.

Changing it to

public abstract class Foo<TFoo> : Foo<TFoo, Bar<TFoo>>
    where TFoo : Foo<TFoo>
{
}

public abstract class Bar<TFoo> : Bar<TFoo, Bar<TFoo>>
    where TFoo : Foo<TFoo>
{
}

will work until the object of type Bar<TFoo> is intantiated (because of it's abtract).

NinjaDeveloper
  • 1,620
  • 3
  • 19
  • 51
KingKerosin
  • 3,639
  • 4
  • 38
  • 77
  • 3
    There's probably too many levels of generics and indirections. I makes my head spin trying to follow which type inherits or implements or is based on or is following the constraint. Is there any chance you can simplify the example? – Lasse V. Karlsen Jun 20 '16 at 15:38
  • Is the point that Foo must not create it's own instance of Bar but have it supplied(constructor) or inherited from FooImpl ? – Terence Jun 20 '16 at 15:38
  • @LasseV.Karlsen I would be glad to have this simplified as my head is spinning since days about this. Any ideas would be greatly appreciated. Not sure if my question makes clear what I'm trying to achieve here... – KingKerosin Jun 20 '16 at 15:45
  • 1
    Is this me or you have an infinite loop ? `abstract class Foo where TFoo : Foo`, then `Foo is equal to Foo, TBar>, TBar>`. How do you even instantiate it ? – romain-aga Jun 20 '16 at 16:00
  • @romain-aga, just what I was thinking. Chickens lay eggs but wait ... – Jodrell Jun 20 '16 at 17:12
  • It's not clear to me how you expect the compiler to verify your circular constraints. This question would be more useful/clear if you could provide compilable (i.e. without errors) example that shows the scenario you're trying to address with the generics, explaining what in that scenario you are trying to fix with the generics. – Peter Duniho Jun 20 '16 at 18:08

1 Answers1

2

I guess you have to end your generic recursion loop:

General interfaces:

public interface IFoo
{
}

public interface IBar
{
}

Depending on what type of inheritance you want:

public interface IFoo<TFoo> : IFoo
    where TFoo : IFoo
{
}

public interface IBar<TBar> : IBar
    where TBar : IBar
{
}

public interface IFoo<TFoo, TBar> : IFoo<IFoo>
    where TFoo : IFoo
    where TBar : IBar
{
}

public interface IBar<TFoo, TBar> : IBar<IBar>
    where TFoo : IFoo
    where TBar : IBar
{
}

Or:

public interface IFoo<TFoo, TBar> : IFoo
    where TFoo : IFoo
    where TBar : IBar
{
}

public interface IBar<TFoo, TBar> : IBar
    where TFoo : IFoo
    where TBar : IBar
{
}

public interface IFoo<TFoo> : IFoo<TFoo, IBar>
    where TFoo : IFoo
{
}

public interface IBar<TBar> : IBar<IFoo, TBar>
    where TBar : IBar
{
}

Abstracts classes:

public abstract class AFoo<TFoo, TBar> : IFoo<TFoo, TBar>
    where TFoo : IFoo
    where TBar : IBar
{
}

public abstract class ABar<TFoo, TBar> : IBar<TFoo, TBar>
    where TFoo : IFoo
    where TBar : IBar
{
}

Implementation classes:

public class Foo<TFoo, TBar> : AFoo<TFoo, TBar>
    where TFoo : IFoo
    where TBar : IBar
{
}

public class Bar<TFoo, TBar> : ABar<TFoo, TBar>
    where TFoo : IFoo
    where TBar : IBar
{
}


public class Foo<TFoo> : AFoo<TFoo, IBar>
    where TFoo : IFoo
{
}

public class Bar<TBar> : ABar<IFoo, TBar>
    where TBar : IBar
{
}

public class Foo : AFoo<IFoo, IBar>
{
}

public class Bar : ABar<IFoo, IBar>
{
}

Usage:

var test = new Foo<IFoo<IFoo<IFoo, IBar<IFoo, IBar>>, IBar>, IBar>();

I still don't understand what you are trying to accomplish here, with a better explanation there should be a better solution.

romain-aga
  • 1,441
  • 9
  • 14