5

I have a generic class and I want to enforce that instances of the type parameter are always "cast-able" / convertible from String. Is it possible to do this without for example using an interface?

Possible implementation:

public class MyClass<T> where T : IConvertibleFrom<string>, new()
{
    public T DoSomethingWith(string s)
    {
        // ...
    }
}

Ideal implementation:

public class MyClass<T>
{
    public T DoSomethingWith(string s)
    {
        // CanBeConvertedFrom would return true if explicit or implicit cast exists
        if(!typeof(T).CanBeConvertedFrom(typeof(String))
        {
            throw new Exception();
        }
        // ...
    }
}

The reason why I would prefer this "ideal" implementation is mainly in order not to force all the Ts to implement IConvertibleFrom<>.

Joaquim Rendeiro
  • 1,388
  • 8
  • 13
  • 3
    what's so ideal about an implementation that reacts to programming-time errors with runtime exceptions? – just somebody Nov 29 '09 at 12:55
  • 1
    if you have a bunch of types that are already converting from string and you want to use them in a new class/method in the way I abstractly described, this would be the least-effort way to implement it. It would be a paint to go edit every type and implement the new interface. – Joaquim Rendeiro Nov 29 '09 at 13:11

3 Answers3

3

Given that you want to convert from the sealed String type, you can ignore possible nullable, boxing, reference and explicit conversions. Only op_Implicit() qualifies. A more generic approach is provided by the System.Linq.Expressions.Expression class:

using System.Linq.Expressions;
...
    public static T DoSomethingWith(string s)
    {
      var expr = Expression.Constant(s);
      var convert = Expression.Convert(expr, typeof(T));
      return (T)convert.Method.Invoke(null, new object[] { s });
    }

Beware the cost of Reflection.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I took the code as it is (but as generic method DoSomethingWith()) and get a NullReferenceException: get_Method returns null. – Patrik Mar 28 '19 at 09:42
-1

Why can't you do something like this?

public class MyClass<T> where T : string
{
    public T DoSomethingWith(string s)
    {
        // ...
    }
}

In this way you can check whether s is convertible to T in the DoSomethingWith code. From there you can throw exception if it can't, or do the casting, if it can

Graviton
  • 81,782
  • 146
  • 424
  • 602
-1
if(!typeof(T).IsAssignableFrom(typeof(String))) {
    throw new Exception();
}
David Hedlund
  • 128,221
  • 31
  • 203
  • 222
  • 2
    Unfortunately doesn't work either with implicit or explicit cast operators declared on argument type. – Joaquim Rendeiro Nov 29 '09 at 13:05
  • hmm, i'm not sure i follow you in your reply. that piece of code would throw an exception if `T` was an int, say, but not if it was a string or an object. is that not what you're after? – David Hedlund Nov 29 '09 at 13:10
  • 1
    I tested it with class MyClass { public static implicit operator MyClass(string s) { return new MyClass(); } } and typeof(MyClass).IsAssignableFrom(typeof(string)) returns false. I assume you expected it to return true... – Joaquim Rendeiro Nov 29 '09 at 13:15