背景#
var x = A?.B?.C?.D?.E;
もし A、B、C、D、または E のいずれかがnull
である場合、x
はnull
と評価されます。
では、どのメンバーの値がnull
であるかを見つける方法はありますか?
方法一:条件チェック#
各メンバーに対して一連の条件チェックを行います:
String findNullMember(A a) {
if (a is null) return "A";
if (a.B is null) return "A.B";
if (a.B.C is null) return "A.B.C";
if (a.B.C.D is null) return "A.B.C.D";
if (a.B.C.D.E is null) return "A.B.C.D.E";
return "";
}
参照元:
- https://www.reddit.com/r/csharp/comments/1b9ojdu/comment/ktx2p2p/?utm_source=share&utm_medium=web2x&context=3
- https://www.reddit.com/r/csharp/comments/1b9ojdu/comment/ktx3fvn/?utm_source=share&utm_medium=web2x&context=3
方法二:Expression 表現#
Expressionを使用して文字列を生成することはできますが、式本体ではnull 条件演算子 (?.)を使用することはできません。
static string FindNullMember<T>(Expression<Func<T>> expression)
{
Stack<MemberExpression> path = new();
Expression? body = expression.Body;
while (body is MemberExpression prop)
{
path.Push(prop);
body = prop.Expression;
}
object? rootObject;
switch (body)
{
case null:
{
// 静的プロパティにアクセス:
rootObject = null;
break;
}
case ConstantExpression c:
{
// インスタンスプロパティにアクセス:
rootObject = c.Value;
if (rootObject is null) return string.Empty;
break;
}
default:
{
throw new ArgumentException($"サポートされていない式です: {expression}", nameof(expression));
}
}
StringBuilder result = new();
foreach (MemberExpression prop in path)
{
if (result.Length != 0) result.Append('.');
result.Append(prop.Member.Name);
switch (prop.Member)
{
case PropertyInfo pi:
{
rootObject = pi.GetValue(rootObject);
break;
}
case FieldInfo fi:
{
rootObject = fi.GetValue(rootObject);
break;
}
default:
{
result.Append("# サポートされていないメンバータイプです: ").Append(prop.Member.GetType().Name).Append('#');
rootObject = null;
break;
}
}
if (rootObject is null) break;
}
return result.ToString();
}
使用方法:
string x = FindNullMember(() => A.B.C.D.E);