---
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` `リフレクション` `式木`