문제

An advantage of generic classes in C# is that one can put constraints on the types so only types who satisfy several constraints are accepted. For instance:

public class Foo<T> where T : Bar, IBaz, IFoobar {

    public Foo (T value) {
        //initialize
    }

}

This means T can only be unified with types who are derived from the three described classes.

When using methods one can make the methods generic as well. I was wondering however why one can't specify such constraint in a constructor. For instance:

public class Foo {

    public Foo (Bar & IBaz & IFoobar value) {
        //initialize (the "&" syntax is just an example)
    }

}

One can make the class generic, but this can be rather cumbersome if only the constructor will use the value and other methods of the class do not depend on T. Some problems might even be difficult to resolve with generic classes for instance one needs to write a comparer SomeComparer<T,Q> : IComparer<Foo<T>,Foo<Q>> introducing loads of generic classes who are in fact not generic at all.

I don't see why this is not implemented since the type system can easily check if an argument satisfies all type constraints.

What are the arguments not to define conjunctive types in the C# language specifications?

도움이 되었습니까?

해결책

That feature might be useful, but just hasn't been implemented. The C# team only has so much time, and I suppose this has just never made the cut. There are a lot of things that make this difficult: let's say you have Foo and Foo<T> classes, and each have non-generic and Foo<U> constructors. If you call new Foo<int>(1), is that Foo..ctor<U> or Foo<T>..ctor? And is Foo<T>..ctor<U> referenced by new Foo<int><string>("")? It can't be done without introducing some new syntax, and confusing any way I can see it being done, so maybe it's best that generics are not allowed on constructors.

You could work around it by writing a generic method on your non-generic class, e.g.

void Main()
{
    Foo foo = Foo.GetInstance(new BarBazAndFoobarImplementer());
}
public sealed class Foo {
    private Foo(Bar value) {
        this.Thing1 = value.BarProperty;
        this.Thing2 = ((IBaz)value).IBazProperty;
        this.Thing3 = ((IFoobar)value).IFoobarProperty;
    }

    public static Foo GetInstance<T>(T value) where T : Bar, IBaz, IFoobar {
        return new Foo(value);
    }
}

(this doesn't suffer from the above problem because you could unambiguously call Foo.GetInstance<U>(..) and Foo<T>.GetInstance<U>(..))

다른 팁

One way something like this could be done, is to use a private constructor and a factory method:

public class Foo 
{
    public static Foo Create<T>(T value) where T : Bar, IBaz, IFoobar
    {
        return new Foo(value);
    }

    private Foo(Bar value)
    {
        // whatever
        // feel free to cast to IBaz or IFoobar as needed
    }
}

You can't do that with a constructor, because a constructor is supposed to construct an instance of its type. What would you do with value? Store it in a field maybe, but what would the type of the field be?

A better way might be that Bar, or a class derived from Bar implements both interfaces.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top