从属性类型中获取属性名称
Posted
技术标签:
【中文标题】从属性类型中获取属性名称【英文标题】:Getting property name from within property type 【发布时间】:2021-12-04 16:03:12 【问题描述】:我不知道如何更好地制定标题。我看到不少帖子标题相似,但讨论的内容完全不同。
所以我们开始吧。实际的实地情况很复杂,但我会尝试发布一个绝对简约的例子来描述它。
假设我们有一个名为Animal
的类:
class Animal
public void Run()
try
//try running
catch(Exception e)
MessageBox.Show(this.SomeCleverWayOfGettingPropertyName() + " failed to run");
现在我在另一个类中定义Animal
类型的几个属性:
class Zoo
public Animal Zebra get; set;
public Animal Lion get; set;
public Animal Rhino get; set;
public void RunAll()
Zebra.Run();
Lion.Run();
Rhino.Run();
我应该写什么来代替 SomeCleverWayOfGettingPropertyName()
让它显示动物的名称(即声明的属性的名称),例如“斑马无法运行”。
正如我所说,实际情况更复杂,所以请避免回答“为什么不重新设计整个代码库,而是尝试 X”之类的答案。我希望在System.Reflection
中找到一些东西来找出调用成员的名字,但我还没有找到类似的东西。
【问题讨论】:
@CodeCaster:嗯……那将是一个障碍。问题是Animal
的实例太多了,所以我试图创建一个集中位置来捕获Run
中的异常。如果我们知道它总是会在属性上而不是局部变量上被调用,它会有所帮助吗?通过强制将其转换为PropertyInfo
或其他什么?
【参考方案1】:
理想情况下,你会重新考虑你的问题,并可能赶在运行之外
根据您的具体需求,表达式可能会起作用。但它确实是一个糟糕的解决方案,如果您竭尽全力,您不妨在外面赶上,或者只是传递成员名称在。
给定
public class Animal
public void Run()
Console.WriteLine("Running");
public static class MemberInfoGetting
public static void Run<T>(this Expression<Func<T>> memberExpression) where T : Animal
var expressionBody = (MemberExpression)memberExpression.Body;
try
var animal = Expression.Lambda<Func<Animal>>(expressionBody).Compile()();
animal.Run();
throw new Exception("bob");
catch
Console.WriteLine($"expressionBody.Member.Name : failed to run");
用法
public static Animal Rhino get; set; = new Animal();
public static void Main()
MemberInfoGetting.Run(() => Rhino);
输出
Running
Rhino : failed to run
【讨论】:
是的。它要求我编辑调用Run
的所有位置,这是我想避免的。但是,谢谢,这是一些聪明的想法。 :)【参考方案2】:
用这种方法基本上是不可能的。当你拨打Zebra.Run()
时会发生什么:
get_Zebra()
方法,将 Zebra 的 Animal 实例指针放入堆栈。
运行时调用Animal.Run()
实例方法。
那时,关于该实例来自何处的所有变量/属性信息都几乎消失了。
现在Animal.Run()
不知道它是在来自属性的实例上调用的,并且不能保证它会被调用。它也可以是本地、方法参数或new()
ed 实例,来自工厂或集合元素。您必须自己传递此信息。
或者,如果它是用于错误处理,它可能比您想象的更容易,而无需解决编译器魔法或昂贵的表达式重构:
在您的异常处理程序中,记录标识 Animal 实例的相关属性。结合堆栈跟踪,这应该可以为您提供足够的信息。
【讨论】:
谢谢。这是一些有见地的信息。我在帖子中没有提到(尽量减少)是我的属性类型为RelayCommand
(MVVM Light)。由于 C# 在内部将属性转换为 get_*
和 set_*
方法,因此只需在我的 Aniaml 的 Run
方法上调用 .Method.Name
即可返回 get_Zebra
(正如您所提到的),这足以满足我的目的。非常感谢您的意见。【参考方案3】:
你可以试试这个:
class Animal
public void Run([CallerMemberName] string caller = null)
try
//try running
catch(Exception e)
MessageBox.Show(caller + " failed to run");
【讨论】:
omg...如果它有效,那就太好了。让我试试。 不,不会,我自己试过了:D 大声笑...是的。它返回调用函数的名称。 你愿意改成这个吗 =>Zebra.Run(nameof(Zebra));
没有。请参阅我在问题下的评论。但谢谢,它确实让我朝着正确的方向前进。【参考方案4】:
唯一合理的方法是更改RunAll()
,使其监控每个调用,到现在修改的运行
class Animal
static readonly Random rng = new Random();
public bool Run()
if (rng.NextDouble() < 0.5)
return false;
return true;
class Zoo
...
public void RunAll()
try
if (!Zebra.Run())
throw new Exception(nameof(Zebra));
if (!Lion.Run())
throw new Exception(nameof(Lion));
if (!Rhino.Run())
throw new Exception(nameof(Rhino));
catch (Exception ex)
Debug.WriteLine($"ex.Message failed to run.");
【讨论】:
以上是关于从属性类型中获取属性名称的主要内容,如果未能解决你的问题,请参考以下文章
从recordset.field.type 属性中获取ADO 数据类型的名称?