tags:

views:

239

answers:

3

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<>.

A: 

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

Ngu Soon Hui
Why use generics at all if you explicitly declare that the generic type has to be a string?
David Hedlund
d, I declared `T` as must be derived from string, this is not the same as saying it must be string.
Ngu Soon Hui
No, I have my own types that can be converted from a string. (PS: you can't inherit from string).
Joaquim Rendeiro
A: 
if(!typeof(T).IsAssignableFrom(typeof(String))) {
    throw new Exception();
}
David Hedlund
Unfortunately doesn't work either with implicit or explicit cast operators declared on argument type.
Joaquim Rendeiro
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
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
+1  A: 

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
This works, thanks!
Joaquim Rendeiro