---
# System prepended metadata

title: C# `ValueTupe` 構造体を動的に生成する方法 2021-10-31
tags: [リフレクション, C#, 式木, ValueTupe]

---

---
lang: ja-jp
breaks: true
---
# C# `ValueTupe` 構造体を動的に生成する方法 2021-10-31

## かなりの力技になるが、以下の方法で動的に生成可能

```csharp=
public class DynamicValueTuple
{
    static ExpressionMethodCache<DynamicValueTuple> s_methodCache;

    static DynamicValueTuple()
    {
        s_methodCache = new();
    }

    // ========================================================================================= //

    private static ValueTuple<T1> Create<T1>()
    {
        return new ValueTuple<T1>(default(T1));
    }
    private static ValueTuple<T1, T2> Create<T1, T2>()
    {
        return new ValueTuple<T1, T2>(default(T1), default(T2));
    }
    private static ValueTuple<T1, T2, T3> Create<T1, T2, T3>()
    {
        return new ValueTuple<T1, T2, T3>(default(T1), default(T2), default(T3));
    }
    private static ValueTuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>()
    {
        return new ValueTuple<T1, T2, T3, T4>(default(T1), default(T2), default(T3), default(T4));
    }
    private static ValueTuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>()
    {
        return new ValueTuple<T1, T2, T3, T4, T5>(default(T1), default(T2), default(T3), default(T4), default(T5));
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>()
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6>(default(T1), default(T2), default(T3), default(T4), default(T5), default(T6));
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>()
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6, T7>(default(T1), default(T2), default(T3), default(T4), default(T5), default(T6), default(T7));
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>> Create<T1, T2, T3, T4, T5, T6, T7, T8>()
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>>(default(T1), default(T2), default(T3), default(T4), default(T5), default(T6), default(T7), new ValueTuple<T8>(default(T8)));
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9>> Create<T1, T2, T3, T4, T5, T6, T7, T8, T9>()
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9>>(default(T1), default(T2), default(T3), default(T4), default(T5), default(T6), default(T7), new ValueTuple<T8, T9>(default(T8), default(T9)));
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9, T10>> Create<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>()
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9, T10>>(default(T1), default(T2), default(T3), default(T4), default(T5), default(T6), default(T7), new ValueTuple<T8, T9, T10>(default(T8), default(T9), default(T10)));
    }

    // ========================================================================================= //

    private static ValueTuple<T1> Create<T1>(T1 ti)
    {
        return new ValueTuple<T1>(ti);
    }
    private static ValueTuple<T1, T2> Create<T1, T2>(T1 t1, T2 t2)
    {
        return new ValueTuple<T1, T2>(t1, t2);
    }
    private static ValueTuple<T1, T2, T3> Create<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
    {
        return new ValueTuple<T1, T2, T3> ( t1, t2, t3);
    }
    private static ValueTuple<T1, T2, T3, T4> Create<T1, T2, T3, T4>(T1 t1, T2 t2, T3 t3, T4 t4)
    {
        return new ValueTuple<T1, T2, T3, T4>(t1, t2, t3, t4);
    }
    private static ValueTuple<T1, T2, T3, T4, T5> Create<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
    {
        return new ValueTuple<T1, T2, T3, T4, T5>(t1, t2, t3, t4, t5);
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6> Create<T1, T2, T3, T4, T5, T6>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6>(t1, t2, t3, t4, t5, t6);
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6, T7> Create<T1, T2, T3, T4, T5, T6, T7>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6, T7>(t1, t2, t3, t4, t5, t6, t7);
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>> Create<T1, T2, T3, T4, T5, T6, T7, T8>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8>>(t1, t2, t3, t4, t5, t6, t7, new ValueTuple<T8>(t8));
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9>> Create<T1, T2, T3, T4, T5, T6, T7, T8, T9>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9>>(t1, t2, t3, t4, t5, t6, t7, new ValueTuple<T8, T9>(t8, t9));
    }
    private static ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9, T10>> Create<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10)
    {
        return new ValueTuple<T1, T2, T3, T4, T5, T6, T7, ValueTuple<T8, T9, T10>>(t1, t2, t3, t4, t5, t6, t7, new ValueTuple<T8, T9, T10>(t8, t9, t10));
    }

    // ========================================================================================= //

    public static object Create(Type[] types)
    {
        int parameterCount = 0;
        if (types != null && types.Any())
        {
            parameterCount = types.Length;
        }

        Type[] genericTypeArguments = types;
        Type[] parameters           = null;
        string methodName           = nameof(Create);

        Delegate func = s_methodCache.GetMethod_Static(
            genericTypeArguments,
            parameters,
            methodName
            );
        return func.DynamicInvoke();
    }

    public static object Create(
        Type[] types,
        object[] values
        )
    {
        int parameterCount = 0;
        if (types != null && types.Any())
        {
            parameterCount = types.Length;
        }

        Type[] genericTypeArguments = types;
        Type[] parameters           = types;
        string methodName           = nameof(Create);

        Delegate func = s_methodCache.GetMethod_Static(
            genericTypeArguments,
            parameters,
            methodName
            );
        return func.DynamicInvoke(values);
    }

    public static ConstructorInfo GetConstructorInfo(Type[] types)
    {
        ConstructorInfo constructorInfo = null;
        if (types != null && types.Any())
        {
            int typeCount = types.Length;
            if (typeCount > 8)
            {
                throw new Exception($"The maximum number of {nameof(ValueTuple)} parameters for which ConstructorInfo can be obtained is 8.");
            }
            object instance = DynamicValueTuple.Create(types);
            if (instance == null)
            {
                throw new Exception($"Failed to get the instance of {nameof(ValueTuple)}.");
            }
            constructorInfo = s_methodCache.GetConstructorInfo(instance.GetType(), types);
            if (constructorInfo == null)
            {
                throw new Exception($"Failed to get the constructor of {nameof(ValueTuple)}.");
            }
        }
        else
        {
            throw new Exception("The number of parameters of the ValueTuple that can obtain ConstructorInfo is one or more.");
        }
        return constructorInfo;
    }
}
```

以下、式木を使った共通的なキャッシュ機構。
```csharp=
public class ExpressionMethodCache<TClass>
{
    private readonly Dictionary<
        Tuple<
            string /* class Type.FullName     */, 
            string /* methodName              */, 
            string /* parameter Type.FullName */
            >, 
        object /* Func */ 
        > m_dicMethod;
    private object   m_lokDic;

    public ExpressionMethodCache()
        : base()
    {
        m_dicMethod = new();
        m_lokDic    = new();
    }
    
    public static ParameterExpression[] GetParameterExpressions(Type[] types)
    {
        if (types == null || types.Any() == false)
        {
            return null;
        }
        ParameterExpression[] expressions = new ParameterExpression[types.Length];
        for (int i = 0; i < types.Length; i++)
        {
            expressions[i] = Expression.Parameter(types[i]);
        }
        return expressions;
    }

    public Delegate GetMethod_Static(
        Type[] genericTypeArguments,
        Type[] parameters,
        string methodName
        )
    {
        string className = typeof(TClass).FullName;

        Type[] parametersType = new Type[0];
        if (genericTypeArguments != null)
        {
            parametersType = parametersType.Concat(genericTypeArguments).ToArray();
        }
        if (parameters != null)
        {
            parametersType = parametersType.Concat(parameters).ToArray();
        }
        string fullname = String.Join("|", parametersType.Select(n => n.FullName));

        var key         = Tuple.Create(className, methodName, fullname);

        Delegate func;
        lock (m_lokDic)
        {
            object obj = null;
            if (m_dicMethod.TryGetValue(key, out obj) == false)
            {
                ParameterExpression[] parameterExpressions = GetParameterExpressions(parameters);

                MethodCallExpression methodCallExpression = Expression.Call(
                    type          : typeof(TClass),
                    methodName    : methodName,
                    typeArguments : genericTypeArguments,
                    arguments     : parameterExpressions
                    );

                LambdaExpression lambda =
                    Expression.Lambda(
                        body       : methodCallExpression,
                        parameters : parameterExpressions
                        );
                func = lambda.Compile();
                m_dicMethod.Add(key, func);
            }
            else
            {
                func = (Delegate)obj;
            }
        }
        return func;
    }

    public ConstructorInfo GetConstructorInfo(
        Type targetType,
        Type[] parameters
        )
    {
        string className = targetType.FullName;
        string fullname = "";
        if (parameters != null && parameters.Any())
        {
            fullname = String.Join("|", parameters.Select(n => n.FullName));
        }
        var key = Tuple.Create(className, nameof(GetConstructorInfo), fullname);

        ConstructorInfo constructorInfo;
        lock (m_lokDic)
        {
            object obj = null;
            if (m_dicMethod.TryGetValue(key, out obj) == false)
            {
                constructorInfo = targetType.GetConstructor(parameters);
                m_dicMethod.Add(key, constructorInfo);
            }
            else
            {
                constructorInfo = (ConstructorInfo)obj;
            }
        }
        return constructorInfo;
    }
    
}
```

###### tags: `C#` `ValueTupe` `リフレクション` `式木`
