How to call a method with a structure constraint with an unknown structure

The question is simple: I use reflection to get the value. Then, if it is a struct, I call the method FooStruct, else FooClass:

Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
    var val = fieldInfo.GetValue(value);
    object obj = type.IsValueType ? val.FooStruct() : val.FooClass();
    fieldInfo.SetValue(x, obj);
}

the problem is that it FooStructhas a limitation:

public static T FooStruct<T>(this T value) where T : struct
{
    //...
}

so the question is: is it possible to call a method with a restriction structon an object that contains an instance with a struct box without reflection?

+4
source share
4 answers

, , , , . . , . . .

: FooStruct FooClass, :

  • , object ( val). , , - object s;

  • val object T FooStruct/FooClass.

, ?. , object ( val), , <T> where T : struct <T> where T : class ( T). foreach. , - , .. T ; , , : mdash, , T.

:

// determine which method ought to be called based on `val` run-time type.
// (for C# 6 and later, use the `nameof` operator instead of hard-coding method names)
Type type = val.GetType();
string fooName = type.IsValueType ? "FooStruct" : "FooClass";

// bind to the generic method and supply the type argument for it:
// (I'm assuming that your extension methods are defined in `FooMethodsClass`.)
MethodInfo fooOpen = typeof(FooMethodsClass).GetMethod(fooName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo foo = fooOpen.MakeGenericMethod(new Type[] { type });

// invoke the generic (extension) method with `val` as the `this` argument:
foo.Invoke(null, new object[] { val });
+2

T . . :

Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
    dynamic val = fieldInfo.GetValue(value);
    object obj = type.IsValueType ? Utilities.FooStruct(val) : Utilities.FooClass(val);
    fieldInfo.SetValue(x, obj);
}
+1

Apparently, you can call reflection methods, and they work without problems:

using System;
using System.Reflection;

namespace DemoDynamicT
{
    public static class Utilities
    {
        public static T FooStruct<T>(this T value) where T:struct
        {
            return default(T);
        }

        public static T FooClass<T>(this T value) where T : class
        {
            return default(T);
        }
    }

    public class Program
    {
        class TestClass
        {
            public TestStruct StructField;
        }

        struct TestStruct
        {
            public int x;
            int y;
        }

        public static void Main()
        {
            var x = new TestClass();
            Type type = x.GetType();
            foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
            {
                var val = fieldInfo.GetValue(x);
                var methodInfo = typeof(Utilities).GetMethod(fieldInfo.FieldType.IsValueType ? "FooStruct" : "FooClass");
                var toBeCalled = methodInfo.MakeGenericMethod(fieldInfo.FieldType);
                object obj = toBeCalled.Invoke(null, new [] {val});
                fieldInfo.SetValue(x, obj);
            }
        }
    }
}
+1
source

I do not think you can do this directly. You can try a workaround as follows:

public static class Utilities
{
    public static ValueType FooStruct(this ValueType value)
    {
        //put your code here
        return default(ValueType);
    }

    public static object FooClass(this object value)
    {
        //put your code here
        return null;
    }

    public static T FooStruct<T>(this T value) where T: struct
    {
        return (T) FooStruct(value);
    }

    public static T FooClass<T>(this T value) where T: class
    {
        return (T) FooClass(value);
    }
}

public class Program
{
    class TestClass
    {
        public TestStruct StructField;
    }

    struct TestStruct
    {
        int x;
        int y;
    }

    public static void Main()
    {
        var x = new TestClass();
        Type type = x.GetType();
        foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
        {
            var val = fieldInfo.GetValue(x);
            object obj = fieldInfo.FieldType.IsValueType ? ((ValueType)val).FooStruct() : val.FooClass();
            fieldInfo.SetValue(x, obj);
        }

        //Generic call
        var structVar = new TestStruct();
        structVar.FooStruct();
    }
}
0
source

All Articles