nameof
演算子は最後の名前しか返しませんが、フルネームを取得したいことは多々あります。
そんななか、stack overflow に便利そうなコードがあったので、そのまま転載します。
例えば、以下のようなクラスがあったとして、
class SpeciesFamily
{
public string Name { get; set; }
}
class Species
{
public SpeciesFamily Family { get; set; }
public string Name { get; set; }
}
class Cat
{
public Species Species { get; set; }
}
Species.Family.Name
という文字列を nameof
演算子を使って取得しようとすると、以下のようなコードになってしまいます。
var fullName = $"{nameof(Species)}.{nameof(Species.Family)}.{nameof(SpeciesFamily.Name)}"
同じクラス名やプロパティ名を何度も書くことになるので、階層が深くなればなるほど面倒です。
これに対して、フルネームを簡単に取得できるようにしたメソッドのサンプルが以下の2つです。
(階層が浅いと記述量はあまり変わりませんが・・・)
サンプルコード1
public static string GetMemberString<T>(System.Linq.Expressions.Expression<Func<T, object>> member)
{
if (member == null)
{
throw new ArgumentNullException("member");
}
var propertyRefExpr = member.Body;
var memberExpr = propertyRefExpr as System.Linq.Expressions.MemberExpression;
if (memberExpr == null)
{
var unaryExpr = propertyRefExpr as System.Linq.Expressions.UnaryExpression;
if (unaryExpr != null && unaryExpr.NodeType == System.Linq.Expressions.ExpressionType.Convert)
{
memberExpr = unaryExpr.Operand as System.Linq.Expressions.MemberExpression;
if (memberExpr != null)
{
return memberExpr.Member.Name;
}
}
}
else
{
//gets something line "m.Field1.Field2.Field3", from here we just remove the prefix "m."
string body = member.Body.ToString();
return body.Substring(body.IndexOf('.') + 1);
}
throw new ArgumentException("No property reference expression was found.", "member");
}
使い方
// Will return a string containing "Species.Family.Name".
var fullName = GetMemberString<Cat>(x => x.Species.Family.Name)
サンプルコード2
public static class NameOf<TSource>
{
#region Public Methods
public static string Full(Expression<Func<TSource, object>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
{
if (expression.Body is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert)
memberExpression = unaryExpression.Operand as MemberExpression;
}
var result = memberExpression.ToString();
result = result.Substring(result.IndexOf('.') + 1);
return result;
}
public static string Full(string sourceFieldName, Expression<Func<TSource, object>> expression)
{
var result = Full(expression);
result = string.IsNullOrEmpty(sourceFieldName) ? result : sourceFieldName + "." + result;
return result;
}
#endregion
}
使い方
// Will return a string containing "Species.Family.Name".
var fullName = NameOf<Cat>.Full(c => c.Species.Family.Name);
// Will return a string containing "cat.Species.Name".
var fullNameWithPrefix = NameOf<Cat>.Full("cat", c => c.Species.Name);
"cat"
のようにプレフィックスが指定できるので、こちらのほうがより汎用的かと思います。
また、"cat"
の部分も nameof
演算子を使えば、文字列の記述を完全に無くすことができます。