问题描述
我正在寻找一种方法来掌握传递给扩展方法的变量的名称.我想在调用变量中包含参数的名称.听起来很奇怪,让我解释一下.
I'm looking for a way to get hold of the name of a variable that was passed into an extensionmethod. I want to have the name of the parameter in the calling variable. Sounds strange, let me explain.
假设这段测试代码
private static void TestingMethod(string firstParam, int secondParam, bool thirdParam)
{
try
{
throw new InvalidOperationException("This named optional params stuff, it's just not working boss");
}
catch (Exception ex)
{
GenericLog_Exception(ex, "it's on fire, please help");
}
}
在最后一行,您可以看到正在记录的异常.我希望能够提供可选的参数支持.因此,开发人员可以在需要时添加参数信息.
On the last line you can see the exception being logged. I want to be able to provide optional parameter support. So the developers can add parameter information when needed.
我在stackoverflow上看到了很多关于此的文章,其中有很多不同的方法.最主要的是它不能完全通用地完成.
I've seen many posts about this on stackoverflow, lot's of different approaches. Main thing is; it can't be done fully generically.
一些说明代码:
static string GetCallingMethodSignature()
{
StackTrace stackTrace = new StackTrace();
// Get calling method name
var callingMethod = stackTrace.GetFrame(1).GetMethod();
var callingMethod_Name = callingMethod.Name;
// get calling method params
string retVal = string.Empty;
var callingMethod_Parameters = callingMethod.GetParameters();
retVal = callingMethod_Name + "(";
foreach (var param in callingMethod_Parameters)
{
retVal += param.Name + ": " + param.ToString() + ",";
}
retVal.Remove(retVal.Length - 1, 1);
retVal += ")";
return retVal;
}
现在,此测试代码正在获取调用方法名称及其参数.即,参数的名称.但不是他们的价值观. param.tostring()部分仅返回类型名称.没有价值.我一直在阅读,似乎无法通过反射来完成.
Now, this testing code is getting the calling method name and it's parameters. That is, the names of the parameters. But not their values. The param.tostring() part only returns the type name. Not the value. I've been reading on this and it seems this can't be done via reflection.
因此,我又去了另一种方法,为什么不提供开发人员认为适合记录的参数.无论如何,您大部分时间都不需要它们.
So then I went for another approach, why not provide the parameters the developer finds suitable for logging. You don't need all of them most of the time anyway.
private static string GenericLog_Exception(Exception exceptionData, string extraInformation, params KeyValuePair<string, object>[] parameters)
因此,这是一个新的测试方法,我将选择的参数提供给异常日志记录方法.但是,如果您想使此工作正常进行,那么每次打电话都是一件难事.
So, this being a new testmethod, i'm providing the parameters of choice into the exception logging method. But if you want to make this work, it's one hell of a job everytime to make this call.
private static void TestingMethod(string firstParam, int secondParam, bool thirdParam)
{
try
{
throw new InvalidOperationException("This named optional params stuff, it's just not working boss");
}
catch (Exception ex)
{
GenericLog_Exception(ex, "it's on fire, please help", new KeyValuePair<string, object>[]{
new KeyValuePair<string, object>("firstParam", firstParam),
new KeyValuePair<string, object>("secondParam", secondParam),
new KeyValuePair<string, object>("thirdParam", thirdParam)
});
}
}
现在这可以了.但是正如我所说,我发现底部很麻烦.我一直在考虑一种扩展方法,因此可以缩短每个kvp的创建时间.
Now this is working. But as said, i find the bottom part to cumbersome. I was thinking along the lines of an extensionmethod, so I can shorten the creation of each kvp.
internal static class ExtensionMethodsForTesting
{
internal static KeyValuePair<string, object> AsKeyValuePair(this string parameter)
{
var name = nameof(parameter);
return new KeyValuePair<string, object>(name, parameter);
}
}
然后将其用作
GenericLog_Exception(ex, "it's on fire, please help", new KeyValuePair<string, object>[] { firstParam.AsKeyValuePair() });
这使我面临以前遇到的相同问题;当然,nameof(parameter)返回"parameter".我还必须为每种类型制作几个扩展方法.或检查扩展方法中的类型,以确保获得正确的值.
This confronts me with the same issue I had before; the nameof(parameter), ofcourse, returns "parameter". I would also have to make a couple of extension methods for each type. Or check for the type in the extension method to make sure i get the correct value.
因此,简而言之:我如何获得调用扩展方法的此变量的名称?
So, in short: how can i get the name of this variable that invokes the extension method?
推荐答案
您可以执行以下黑客"操作.将您的方法的签名更改为以下内容:
You could do the following "hack". Change the signature of your method to the following:
private static string GenericLog_Exception(
Exception exceptionData,
string extraInformation,
params Expression<Func<object>>[] parameters)
现在您的呼叫站点看上去会更加干净:
And now your call site would look a little bit cleaner:
GenericLog_Exception(ex,
"it's on fire, please help",
() => firstParam,
() => secondParam,
() => thirdParam);
您可以通过以下方式从表达式中提取参数信息(为方便起见,使用C#元组支持):
And you can extract parameter info from the expressions the following way (using C# tuple support for convenience):
private static (object Value, string ParamName) GetParameterInfo
(Expression<Func<object>> expr)
{
//First try to get a member expression directly.
//If it fails we know there is a type conversion: parameter is not an object
//(or we have an invalid lambda that will make us crash)
//Get the "to object" conversion unary expression operand and then
//get the member expression of that and we're set.
var m = (expr.Body as MemberExpression) ??
(expr.Body as UnaryExpression).Operand as MemberExpression;
return (expr.Compile().Invoke(), m.Member.Name);
}
这篇关于从调用方法中的变量获取名称-创建调用方法签名,参数和值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!