简体   繁体   中英

Cast to Type with reflection without generic argument

I have an issue which involves casting to different Types

I have a class which is a wrapper, which contains an inner wrapper which contains T here is the structure:

public class Wrapper
{
    public readonly Guid Foo;

    public Wrapper(Guid foo)
    {
        Foo = foo;
    }
}

public class Wrapper<T> : Wrapper
{
    public readonly InnerWrapper<T> InnerWrapper;

    public Wrapper(Guid foo, InnerWrapper<T> innerWrapper) 
        : base(foo)
    {
        InnerWrapper = innerWrapper;
    }
}

public class InnerWrapper<T> 
{
    public readonly Guid Bar;
    public readonly T Content;
    public InnerWrapper(T content, Guid bar)
    {
        Content = content;
        Bar = bar;
    }
}

In another part of the code I have a List<Wrapper> . notice that is a list of wrapper not a list of wrapper<T> which means that T can be any class. when this translates is expected to have something like

{
    wrapper<Class1>,
    wrapper<Class2>
}

and so on.

At some point in the code there is a "helper class" which contains the object as object type and the Type

public class Helper
{
    public readonly object Obj;
    public readonly Type Type;

    public Helper(object obj, Type type)
    {
        Obj = obj;
        Type = type;
    }
}

And here is where my problem begins, I created a helper method to convert from List<Helper> to List<Wrapper> and it does it, but the inner object is type object instead of being the actual type.

And i have no clue of how to convert from object to the actual type without using generics, and as T can be multiples types I cannot use them.

This is the helper classs

public static class HelperExtensions
{
    public static T CastTo<T>(this object o) => (T)o;

    public static List<Wrapper> ToWrapper(this IEnumerable<Helper> helperList)
    {
        List<Wrapper> wrapperResponseList = new List<Wrapper>();
        foreach (var help in helperList)
        {
            // doesn't work either var typedValue = Convert.ChangeType(help.Obj, help.Type);

            var methodInfo = typeof(HelperExtensions).GetMethod(nameof(CastTo), BindingFlags.Static | BindingFlags.Public);
            var genericArguments = new[] { help.Type };
            var genericMethodInfo = methodInfo?.MakeGenericMethod(genericArguments);
            var typedValue = genericMethodInfo?.Invoke(null, new[] { help.Obj });

            var wrapper = typedValue.BuildWrapper(Guid.NewGuid(), Guid.NewGuid());

            wrapperResponseList.Add(wrapper);
        }

        return wrapperResponseList;
    }


    //This one called individually does the work properly
    public static Wrapper<T> BuildWrapper<T>(this T obj, Guid foo, Guid bar)
    {
        InnerWrapper<T> inner = new InnerWrapper<T>(obj, bar);
        return new Wrapper<T>(foo, inner);
    }

}

to show the code here I also Created a test class

public class Placeholder
{
    public Guid Value { get; }

    public Placeholder(Guid value)
    {
        Value = value;
    }
}

so when I call

Placeholder placeholder = new Placeholder(Guid.NewGuid());
Helper helper1 = new Helper(placeholder, placeholder.GetType());
var result = new List<Helper> { helper1 }.ToWrapper();

It generates a List<Wrapper> but instead of wrapper<T> it is generating Wrapper<Object>

Any idea how can I cast it properly?

I also created a fiddle https://dotnetfiddle.net/pz3JDz which contains all the needed code to test.

Thanks In advance for your help.

The local variable typedValue is declared with var and because genericMethodInfo?.Invoke(...) returns the reply of the type object , the type of that local variable typedValue will be object . After that you call the generic method Wrapper<T> BuildWrapper<T>(this T obj, ...) here since the type of typedValue is object the type of T is will also be object , therefore it will return Wrapper<object> .

To solve it instead of this:

var wrapper = typedValue.BuildWrapper(Guid.NewGuid(), Guid.NewGuid());

Do this:

var buildWrapperMethodInfo = typeof(HelperExtensions).GetMethod(nameof(BuildWrapper), BindingFlags.Static | BindingFlags.Public);
var buildWrapperGenericMethodInfo = buildWrapperMethodInfo?.MakeGenericMethod(genericArguments);
var wrapper = buildWrapperGenericMethodInfo?.Invoke(null, new[] { typedValue, Guid.NewGuid(), Guid.NewGuid() });

And then add the type cast here:

wrapperResponseList.Add((Wrapper)wrapper);

Simplifying the call to directly retrieve the object from the BuildWrapper<T> is possible. You can do the following. You can obviously reformat for error check but you get the idea.

var wrapperGeneric = typeof(HelperExtensions).GetMethod("BuildWrapper").MakeGenericMethod(new[] { help.Type}).Invoke(this,help.Obj)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM