tags:

views:

92

answers:

4

Suppose I write a library with the following:

public class Bar { /* ... */ }

public class SomeWeirdClass<T>
    where T : ???
{
    public T BarMaker(Bar b)
    {
        // ... play with b
        T t = (T)b
        return (T) b;
    }
}

Later, I expect users to use my library by defining their own types which are convertible to Bar and using the SomeWeirdClass 'factory'.

public class Foo
{
    public static explicit operator Foo(Bar f)
    {
        return new Bar();
    }
}

public class Demo
{
    public static void demo()
    {
        Bar b = new Bar();
        SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>();
        Foo f = weird.BarMaker(b);
    }
}

this will compile if i set where T : Foo but the problem is that I don't know about Foo at the library's compile time, and I actually want something more like where T : some class that can be instantiated, given a Bar

Is this possible? From my limited knowledge it does not seem to be, but the ingenuity of the .NET framework and its users always surprises me...

This may or not be related to the idea of static interface methods - at least, I can see the value in being able to specify the presence of factory methods to create objects (similar to the same way that you can already perform where T : new())

edit: Solution - thanks to Nick and bzIm - For other readers I'll provide a completed solution as I understand it: edit2: This solution requires Foo to expose a public default constructor. For an even stupider better solution that does not require this see the very bottom of this post.

public class Bar {}

public class SomeWeirdClass<T>
    where T : IConvertibleFromBar<T>, new()
{
    public T BarMaker(Bar b)
    {
        T t = new T();
        t.Convert(b);
        return t;
    }
}

public interface IConvertibleFromBar<T>
{
    T Convert(Bar b);
}

public class Foo : IConvertibleFromBar<Foo>
{
    public static explicit operator Foo(Bar f)
    {
        return null;
    }

    public Foo Convert(Bar b)
    {
        return (Foo) b;
    }
}

public class Demo
{
    public static void demo()
    {
        Bar b = new Bar();
        SomeWeirdClass<Foo> weird = new SomeWeirdClass<Foo>();
        Foo f = weird.BarMaker(b);
    }
}

edit2: Solution 2: Create a type convertor factory to use:

#region library defined code

public class Bar {}

public class SomeWeirdClass<T, TFactory>
    where TFactory : IConvertorFactory<Bar, T>, new()
{
    private static TFactory convertor = new TFactory();

    public T BarMaker(Bar b)
    {
        return convertor.Convert(b);
    }
}

public interface IConvertorFactory<TFrom, TTo>
{
    TTo Convert(TFrom from);
}

#endregion

#region user defined code

public class BarToFooConvertor : IConvertorFactory<Bar, Foo>
{
    public Foo Convert(Bar from)
    {
        return (Foo) from;
    }
}

public class Foo
{
    public Foo(int a) {}

    public static explicit operator Foo(Bar f)
    {
        return null;
    }

    public Foo Convert(Bar b)
    {
        return (Foo) b;
    }
}

#endregion

public class Demo
{
    public static void demo()
    {
        Bar b = new Bar();
        SomeWeirdClass<Foo, BarToFooConvertor> weird = new SomeWeirdClass<Foo, BarToFooConvertor>();
        Foo f = weird.BarMaker(b);
    }
}
+2  A: 

I don't think there is necessarily a syntactically cool way to do this built into the language. One possible solution to your problem could be to define a convertible interface:

public interface IConvertible<T>
    where T :  new()   // Probably will need this
{
    T Convert();
}

Then your class could be:

public class Foo : IConvertible<Bar>
{
}

I think this gets you close to where you want to be... All the Foo's and Bar's in your question sometimes make it hard to determine exactly what your intent is. Hope this helps.

Edit: Added where constraint... you will probably have to be able to create a new instance in your convertible class.

Edit 2: Made Foo inherit from ICovertible<Bar>

Nick
My understanding is then I define a Foo : IConvertible<Bar>? That will allow me to convert Foo instances to Bar instances, but I actually want to convert Bar instances to Foo instances. I think I would actually need to implement Bar : IConvertible<Foo> - but of course not knowing Foo at library-compile-time I cannot do this.
fostandy
And my apologies for the abstraction. I do try to avoid that where possible but the specific application of this is somewhat convoluted in and of itself.
fostandy
@fostandy - To be honest, I'm having a hard time understanding exactly what you are trying to do, especially with the Foos, Bars, and saying you don't know Foo at library compile time? Can you un-obfuscate your question a bit?
Nick
@fostandy - I made another edit... couldn't you just make Foo implement `IConvertible<Bar>`?
Nick
Ignore the first comment. I understand what you are saying now. Will update OP with accordingly. Thanks!
fostandy
+1  A: 

You could make a detour via an interface which is used as a type constraint.

For example, where T : IComparable<U> is used to constrain the type to something that can be compared to another thing, which must express this ability by implementing IComparable<another>. If you had an interface ICastableFrom<T>, you could achieve what you want by forcing them to implement ICastableFrom<Bar>.

bzlm
+2  A: 

Sounds like you found a solution to the larger problem. To answer your specific question: no, neither C# nor the CLR support the "backwards" generic type parameter constraint. That is,

class C<T> where Foo : T

"T must be Foo or a type which Foo converts to" is not supported.

There are languages that have that sort of constraint; IIRC Scala is such a language. I suspect this feature would be handy for certain uses of contravariant interfaces.

Eric Lippert
+1  A: 

Rather than go through the trouble of defining an interface and modifying your class to implement that interface, why not just do this?

public class SomeWeirdClass<T>
{
    // aside: why is this method called 'BarMaker' if it returns a T?
    public T BarMaker(Bar b, Func<Bar, T> converter)
    {
        // ... play with b
        return converter(b);
    }
}

Then in the event that you are dealing with an object of a type T to which Bar can be directly cast, this method could be called simply as follows:

var someWeirdObject = new SomeWeirdClass<Foo>();
var someBar = new Bar();
var someFoo = someWeirdObjcet.BarMaker(someBar, bar => bar as Foo);

By the way (since the Func<T, TResult> delegate emerged in .NET 3.5), you could also use Converter<TInput, TOutput> (which is exactly the same) for the converter parameter.

Dan Tao
Excellent point. I guess I got so fixated on generics and constraints I completely missed this.
fostandy