0

I found this question: Is it possible to specify a generic constraint for a type parameter to be convertible FROM another type? I am looking for a smarter way.

Class A {
     public A(string){}
}

Class foo
{
    private List<A> content = new List<A>();

    public void Add(A a){
        content.Add(a);
    }
    public void Add(string str){
        content.Add(new A(str));
    }
    public void AddRange<T>(IEnumerable<T> iterable) // where T : ???
    {
        foreach(T t in iterable)
            content.Add((A)t); //Error
    }
}

The Error is:

Cannot convert type 'T' to 'A'

Question: Exists a where T : ? expression like "convertable"?

Update: I have two method overloadings: Add(A)and Add(string) Currently i try to convert T to A. But my main problem is, that i want to use different Addmethods relating to T. What i need is something like:

public void AddRange<T>(IEnumerable<T> iterable) where T : Add(T) 
{
    foreach (T t in iterable)
        this.Add(t);
}
Syrlia
  • 154
  • 2
  • 14
  • 7
    It's not clear what you're trying to achieve. Don't you just want `where T : A`? – Jon Skeet Aug 04 '17 at 13:13
  • What does it mean "convertable"? – Roman Aug 04 '17 at 13:13
  • I want call Add with two different enumerable types: List and List. – Syrlia Aug 04 '17 at 13:15
  • Additional to the previous comments you should consider to name your method `AddRange` as you´re adding multiple items to your list in contrast to `Add` which will add only a single item. – MakePeaceGreatAgain Aug 04 '17 at 13:17
  • @Rahul, i did, but the error still exists. But `T` could be everything. For example an integer isn't convertable. So the error is okay. I need to limit `T` to solve it. I don't know how i can say: `T` is every type which can be converted (impl/expl) to `A`. – Syrlia Aug 04 '17 at 13:20
  • @Syrlia . and what is A in your last comment? – kuskmen Aug 04 '17 at 13:25

3 Answers3

3

I think what you are looking for constraint to type that has to have explicit operator T, but since specification says:

conversion-operator-declarator:
    implicit   operator   type   (   type   identifier   )
    explicit   operator   type   (   type   identifier   )

which generally means you cant have generic explicit and implicit operator, I don't think this is possible.

You can make your case possible if you have some concrete types however like so:

public class A
{
    public static explicit operator B(A a)
    {
        return new B();
    }
}

public class B { }

public class Convert
{
    public static T To<T>(dynamic obj)
    {
        return (T) obj;
    }
}

class Foo
{
    private List<A> content = new List<A>();
    public void AddRange<T>(IEnumerable<T> iterable) where T : B
    {
        foreach (T t in iterable)
            content.Add(Convert.To<A>(t)); // This will invoke the implicit operator defined in A
    }
}

Maybe you can abstract your generic T types to be of type B type and constrain it like that, or maybe you define all implicit operators of types that want you to convert to A in type T.

kuskmen
  • 3,648
  • 4
  • 27
  • 54
1

If you want T to be the type A or any derived type use where T : A.

EDIT(after your comment):

If you want T to be A or String you can't do something like this: where T : A, String. You can constraint only class, interface, type, but it is not possible to do OR operation.

So, in your case if you want only String or A then you should use different implementations. If you want any class - where T : class

Roman
  • 11,966
  • 10
  • 38
  • 47
  • I got this error: 'string' is not a valid constraint. A type used as a constraint must be an interface, a non-sealed class or a type parameter. – Syrlia Aug 04 '17 at 13:27
  • @Syrlia, when do you get this error? If you try to constraint to accept only `String` you will fail because `String` is `sealed` and constraints on `sealed` classes are not allowed (no reason for it). Saying different implementations I mean two overloads - if you want only two types you should have two overloads - there is no need in generics in this case. – Roman Aug 04 '17 at 13:44
  • Two more implementations are no problem, but i want to learn it for bigger cases. This is only an example. ;-) I got the error while change it to: `AddRange(IEnumerable iterable) where T : A, string` – Syrlia Aug 04 '17 at 13:52
  • 1
    @Syrlia, but you can't specify two class constraints (see in answer). If you really need generics then you should use answer in the link you provided. – Roman Aug 04 '17 at 13:57
0

You can use A instead of T:

public void Add(IEnumerable<A> iterable)
{
   foreach(A t in iterable)
      content.Add(t);
}

and:

public void Add(IEnumerable<string> iterable)
{
   foreach(string t in iterable)
      content.Add(t);
}
Daria Pydorenko
  • 1,754
  • 2
  • 18
  • 45
  • If i do and try to call `AddRange(new List()`: "Argument 1: cannot convert from 'System.Collections.Generic.List' to System.Collections.Generic.IEnumerable' " – Syrlia Aug 04 '17 at 13:31
  • You must add two methods, because 'string' is not a valid constraint (for where clause) as it is a sealed class. – Daria Pydorenko Aug 04 '17 at 13:39