views:

105

answers:

4

I meet a problem about type contraint of c# now.

I wrote a pair of methods that can convert object to string and convert string to object. ex.

static string ConvertToString(Type type, object val) {
 if (type == typeof(string)) return (string)val;
 if (type == typeof(int)) return val.ToString();
 if (type.IsSubclassOf(typeof(CodeObject))) return ((CodeObject)val).Code;
}

static T ConvertToObject<T>(string val) {
 Type type = typeof(T);
 if (type == typeof(string)) return (T)(object)val;
 if (type == typeof(int)) return (T)(object)int.Parse(val);
 if (type.IsSubclassOf(typeof(CodeObject))) return Codes.Get<T>(val);
}

where CodeObject is a base class of Employees, Offices ..., which can fetch by static method Codes.Get where T: CodeObject

but the code above cannot be compiled because error #CS0314

the generic type T of method ConvertToObject have no any constraint but Codes.Get request T must be subclass of CodeObject

i tried use overloading to solve the problem but not ok.

is there any way to clear up the problem? like reflection?

A: 

You want to add a type constraint, like so:

static T ConvertToObject<T>(string str) where T : CodeObject
{
    Type type = typeof(T);
    if (type == typeof(string)) return (T)(object)val;
    if (type == typeof(int)) return (T)(object)int.Parse(val);
    if (type.InSubclassOf(typeof(CodeObject))) return Codes.Get<T>(val);
}

The type constraint is there "where T" bit. You're basically telling the compiler that T must be a subclass of CodeObject.

Dean Harding
Seems good, but then it cannot return `int` or `object`. The casting method is probably the right answer here.
Kobi
If T is constrained to CodeObject, then T cannot be int or string.
Anthony Pegram
Oh yeah, I missed that part. I think John Weldon's answer is the best in that case.
Dean Harding
A: 

Your conversion method must have identical constraints to be able to call the Codes.Get<T> and satisfy your constraints for <T>.

Try this:

static T ConvertToObject<T>(string str) where T:CodeObject
{
   return Codes.Get<T>(str);
}

Edit: As someone pointed out, now that you have the constraint, will never be int, or string. In addition, the check to make sure it is of type CodeObject is done by the constraint.

This essentially makes the wrapping method "extra" and not needed. Simply call Codes.Get unless you have a good reason for abstracting it.

Hope this helps.

Anderson Imes
+2  A: 

I think your function signature needs a type constraint; but since all permutations don't need that constraint I'd make a helper function; something like:

static T ConvertToObject<T>(string str) {
 Type type = typeof(T);
 if (type == typeof(string)) return (T)(object)val;
 if (type == typeof(int)) return (T)(object)int.Parse(val);
 if (type.InSubclassOf(typeof(CodeObject))) return ConvertCodeObjectToObject((CodeObject)val);
}

static T ConvertCodeObjectToObject<T>(string str) where T: CodeObject {
 return Codes.Get<T>(val);
}

I think you have to cast the param to ConvertCodeObjectToObject, because of the Type constraint.

John Weldon
If you perform the cast, The type for T will always be CodeObject. Depending on the implementation of Codes.Get<T> this could make a significant difference.
Anderson Imes
I should be clear... <T> will always be of type CodeObject and never any of its subclasses.
Anderson Imes
Thank you! however, since method defined as ConvertCodeObjectToObject<T>(string),i have to return ConvertCodeObjectToObject''''<T>''''((CodeObject)val). and the same #CS0314 problem occured.
but
A: 

i tried to clear up the problem by reflection.

if (type.IsSubclassOf(typeof(CodeObject))) {
    var baseMethod = typeof(Codes).GetMethod("Fetch<>", BindingFlags.Static | BidingFlags.Public, null, new Type[] {typeof(string)}, null);
    if (baseMethod != null) {
        var genericMethod = baseMethod.MakeGenericMethod(type);
        if (genericMethod != null)
            return (T)genericMethod.Invoke(null, new string[] { val });
    }
}
but