Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generics explicit conversion

I implemented an explicit conversion from string to object called Foo.

So => Foo f = (Foo)"foo data"; works

I need to implement a function that cast a string to the generic T, T in this case is Foo datatype.

public T Get<T>(object o){
      // this always return false
      if (typeof(T).IsAssignableFrom(typeof(String)))
      {
            // when i by pass the if above this throws invalid cast exception
            return (T)(object)str;
      }
      return null; 
}

// When I call this, it generated an error
// Invalid cast from 'System.String' to Foo
Foo myObj = Get<Foo>("another foo object"); 

// when I use the dynamic keyword it works but this is C# 4.0+ feature, my function is in the older framework
return (T)(dynamic)str;
like image 525
Du D. Avatar asked Apr 19 '13 22:04

Du D.


People also ask

Is it possible to inherit from a generic type?

An attribute cannot inherit from a generic class, nor can a generic class inherit from an attribute.

What are generic constraints in c#?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function. Constraints can specify interfaces, base classes, or require a generic type to be a reference, value, or unmanaged type.

What is generics in asp net?

Generics are classes, structures, interfaces, and methods that have placeholders (type parameters) for one or more of the types that they store or use. A generic collection class might use a type parameter as a placeholder for the type of objects that it stores.

Does C# support generics?

C# allows you to define generic classes, interfaces, abstract classes, fields, methods, static methods, properties, events, delegates, and operators using the type parameter and without the specific data type.


2 Answers

An example that uses Reflection:

class Program
{
    static void Main(string[] args)
    {           
        Foo myObj = TypeResolver.Get<Foo>("Foo data");            
    }
}

class TypeResolver
{
    public static T Get<T>(object obj)
    {
        if (typeof(T).CanExplicitlyCastFrom<string>())
        {                             
            return obj.CastTo<T>();
        }
        return default(T);
    }
}

public static class Extensions
{
    public static bool CanExplicitlyCastFrom<T>(this Type type)
    {
        if (type == null)
            throw new ArgumentNullException("type");

        var paramType = typeof(T);
        var castOperator = type.GetMethod("op_Explicit", 
                                        new[] { paramType });
        if (castOperator == null)
            return false;

        var parametres = castOperator.GetParameters();
        var paramtype = parametres[0];
        if (paramtype.ParameterType == typeof(T))
            return true;
        else
            return false;
    }

    public static T CastTo<T>(this object obj)
    {            
        var castOperator = typeof(T).GetMethod("op_Explicit", 
                                        new[] { typeof(string) });
        if (castOperator == null)
            throw new InvalidCastException("Can't cast to " + typeof(T).Name);
        return (T)castOperator.Invoke(null, new[] { obj });
    }
}
like image 178
anouar.bagari Avatar answered Sep 29 '22 05:09

anouar.bagari


Also take a look at this answer from @Jon Skeet - and specifically the quote about IsAssignableFrom.

I don't think that's possible in a way that you envisioned it.

I'd suggest you put an 'interface contract' on your Foo classes - and then let generics do their work.

e.g. something like this - but this is just a fast solution I typed in...

class Factory 
{
    public static T Create<T, TVal>(TVal obj) where T : class, IFoo<TVal>, new()
    {
        return new T { Value = obj }; // return default(T);
    }
}
interface IFoo<TVal>
{
    TVal Value { get; set; }
}
class Foo : IFoo<string>
{
    public string Value { get; set; }
    public Foo() { }
}
// ...
public T Get<T, TVal>(TVal obj) where T : class, IFoo<TVal>, new()
{
    return Factory.Create<T, TVal>(obj);
}

And you can call it in a similar way - providing that you have that luxury - know the types etc.
(but you can work this out and adjust if needed)

Foo foo = Get<Foo, string>("another text");
like image 43
NSGaga-mostly-inactive Avatar answered Sep 29 '22 05:09

NSGaga-mostly-inactive