使用自定义属性跳过正文方法
Use custom attribute to skip body method
我有以下功能:
public void Test(string testString)
{
//Do Stuff
}
在我的代码中的某些地方,我必须反复检查参数是否为空 string/null/whitespace 以跳过 body 方法。到目前为止,我常用的方法如下:
public void Test(string testString)
{
if(!string.IsNullOrWhiteSpace(testString))
{
//Do Stuff only if string has text in it.
}
}
或
public void Test(string testString)
{
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
有没有办法创建一个自定义属性来检查函数的参数是否为空等,以跳过该方法?我有一些经验(基本的东西),有自定义属性,但我想不出让属性跳过方法体的方法。
实施的理想最终产品如下:
[SkipIfEmptyParameter]
public void Test(string testString)
{
//Do Stuff only if string has text in it.
}
当然,如果属性实现不可能,欢迎任何有助于最小化重复代码的建议。
编辑:我要解决的问题示例。
我有以下方法。我从 Microsoft 测试管理器获得了我们的测试场景期望的一些参数(值应该是什么)。有一个断言用户信息的 SharedStep 实现:
public void AssertUser(UserDTO expectedUserInfo)
{
VerifyUserName(expectedUserInfo.name);
VerifyUserSurname(expectedUserInfo.surname);
VerifyUserAge(expectedUserInfo.age);
VerifyUserHeight(expectedUserInfo.height);
}
private void VerifyUserName(string name)
{
//If the string parameter is empty, means the MTM scenario does not
//want to validate the user's name at this point, so skip the
//verification below.
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
private void VerifyUserSurname(string surname)
{
//If the string parameter is empty, means the MTM scenario does not
//want to validate the user's surname at this point, so skip the
//verification below.
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
private void VerifyUserAge(string age)
{
//If the string parameter is empty, means the MTM scenario does not
//want to validate the user's age at this point, so skip the
//verification below.
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
private void VerifyUserHeight(string height)
{
//If the string parameter is empty, means the MTM scenario does not
//want to validate the user's height at this point, so skip the
//verification below.
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
"Do Stuff" 包含处理 WebElements 的 Selenium 实现并且可能很耗时,因此如果我们不想验证该特定值,我们只需跳过整个方法。
现在,在为 Microsoft 测试管理器创建场景时,共享步骤允许测试人员决定将验证页面的哪些元素。如果某些参数为空,则代码将跳过块并转到 w/e 用户想要的验证(仍然,实现是针对用户拥有的每个信息,但我们只是为每个想要的参数赋值进行测试,每个没有值的参数都将跳过它的方法体。
问题是,如果我想改变跳过方法的条件,我将不得不转到每个方法并手动更改 IF 语句。因此,为什么我认为为每个验证信息的方法设置一个属性可能是个好主意。
P.S。我说的是数百种一开始就有 IF 实现的方法。
我认为属性无法实现您想要实现的目标。
但您可以改用自定义方法调用程序:
static void Main(string[] args)
{
InvokeIfNotNullOrWhitespace((inputStr) => TestMethod(inputStr), null);
InvokeIfNotNullOrWhitespace((inputStr) => TestMethod(inputStr), "");
InvokeIfNotNullOrWhitespace((inputStr) => TestMethod(inputStr), "abc");
// RESULT:
// Trying to invoke action...
// Trying to invoke action...
// Trying to invoke action...
// I have been invoked!
}
static void InvokeIfNotNullOrWhitespace(Action<string> action, string inputString)
{
Console.WriteLine("Trying to invoke action...");
if(!string.IsNullOrWhiteSpace(inputString))
action.DynamicInvoke(inputString);
}
static void TestMethod(string input)
{
Console.WriteLine("I have been invoked!");
}
我认为属性不起作用的原因是它们无法控制方法内部发生的事情。相反,"other external things" 可以查看这些属性并决定要做什么。
要实现您想要实现的目标,"external thing" 需要查看属性并决定是否执行它。这相当于我写的:统一 "check string validity" 过程的外部调用程序。
据我所知,可以使用属性完成此操作的唯一方法是使用 post sharp 和方法 interception. Alternatively if the methods are defined in an interface this can also be done by using RealProxy 之类的产品进行面向方面的编程,但似乎有点矫枉过正。
这是我的 4 美分,
- 调用属性涉及反射,已经是个坏主意了
您需要查明该属性是否已设置;
- 你在你的代码中避免了 "1 liner" 实际上是
易于输入;
- 使用方法重载;
- 您可以使用 Aspect oriented programming,它基本上会在编译时将以下示例注入您的代码中。您可以控制它与注释一起工作的方式,并且不会对生成的运行时产生负面影响。
这里有一些变化:
//1
if(string.IsNullOrEmpty(testString))
return;
//2
if(string.IsNullOrEmpty(testString) ||string.IsNullOrWhiteSpace(testString) )
return;
选择 3 时,请确保不要混合返回 null 或基于 "missing" 文本的布尔值 true/false。只有您知道您的代码应该如何流动。
也许您正在寻找方法重载
您可以通过在同一个 class 中创建两个具有相同名称的方法来做到这一点。
您可以从 MyMethod(带有字符串)调用空的 MyMethod(),这样您就不会重复逻辑。
return string.IsNullOrEmpty(testString)?MyMethod():MyMethod(testString);
你的做法其实很不错。但正如 Evk 在评论中指出的那样:您应该将 "skip checking" 提取到一个单独的方法中,尤其是在检查始终相同且需要全局更改的情况下。使用属性可以解决问题,但使用起来有点复杂。
相反,请查看下面的代码。看起来很清楚,不是吗?不要使用太多注释(也不要将它们复制粘贴到每个方法中,那是没有用的)。这样,您将获得与使用自定义属性相同的好处,但没有使用反射的丑陋之处。
public void AssertUser(UserDTO expectedUserInfo)
{
VerifyUserName(expectedUserInfo.name);
VerifyUserSurname(expectedUserInfo.surname);
VerifyUserAge(expectedUserInfo.age);
VerifyUserHeight(expectedUserInfo.height);
}
private void VerifyUserName(string name)
{
if (ShouldSkipValidation(name)) return;
// code here...
}
private void VerifyUserSurname(string surname)
{
if (ShouldSkipValidation(surname)) return;
// code here...
}
private void VerifyUserAge(string age)
{
if (ShouldSkipValidation(age)) return;
// code here...
}
private void VerifyUserHeight(string height)
{
if (ShouldSkipValidation(height)) return;
// code here...
}
// The MTM scenario does not want to validate values that satisfy the check below
private bool ShouldSkipValidation(string value)
{
return string.IsNullOrWhiteSpace(value) || value == "<>";
}
我有以下功能:
public void Test(string testString)
{
//Do Stuff
}
在我的代码中的某些地方,我必须反复检查参数是否为空 string/null/whitespace 以跳过 body 方法。到目前为止,我常用的方法如下:
public void Test(string testString)
{
if(!string.IsNullOrWhiteSpace(testString))
{
//Do Stuff only if string has text in it.
}
}
或
public void Test(string testString)
{
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
有没有办法创建一个自定义属性来检查函数的参数是否为空等,以跳过该方法?我有一些经验(基本的东西),有自定义属性,但我想不出让属性跳过方法体的方法。
实施的理想最终产品如下:
[SkipIfEmptyParameter]
public void Test(string testString)
{
//Do Stuff only if string has text in it.
}
当然,如果属性实现不可能,欢迎任何有助于最小化重复代码的建议。
编辑:我要解决的问题示例。
我有以下方法。我从 Microsoft 测试管理器获得了我们的测试场景期望的一些参数(值应该是什么)。有一个断言用户信息的 SharedStep 实现:
public void AssertUser(UserDTO expectedUserInfo)
{
VerifyUserName(expectedUserInfo.name);
VerifyUserSurname(expectedUserInfo.surname);
VerifyUserAge(expectedUserInfo.age);
VerifyUserHeight(expectedUserInfo.height);
}
private void VerifyUserName(string name)
{
//If the string parameter is empty, means the MTM scenario does not
//want to validate the user's name at this point, so skip the
//verification below.
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
private void VerifyUserSurname(string surname)
{
//If the string parameter is empty, means the MTM scenario does not
//want to validate the user's surname at this point, so skip the
//verification below.
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
private void VerifyUserAge(string age)
{
//If the string parameter is empty, means the MTM scenario does not
//want to validate the user's age at this point, so skip the
//verification below.
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
private void VerifyUserHeight(string height)
{
//If the string parameter is empty, means the MTM scenario does not
//want to validate the user's height at this point, so skip the
//verification below.
if(string.IsNullOrWhiteSpace(testString)) { return; }
//Do Stuff only if string has text in it.
}
"Do Stuff" 包含处理 WebElements 的 Selenium 实现并且可能很耗时,因此如果我们不想验证该特定值,我们只需跳过整个方法。
现在,在为 Microsoft 测试管理器创建场景时,共享步骤允许测试人员决定将验证页面的哪些元素。如果某些参数为空,则代码将跳过块并转到 w/e 用户想要的验证(仍然,实现是针对用户拥有的每个信息,但我们只是为每个想要的参数赋值进行测试,每个没有值的参数都将跳过它的方法体。
问题是,如果我想改变跳过方法的条件,我将不得不转到每个方法并手动更改 IF 语句。因此,为什么我认为为每个验证信息的方法设置一个属性可能是个好主意。
P.S。我说的是数百种一开始就有 IF 实现的方法。
我认为属性无法实现您想要实现的目标。
但您可以改用自定义方法调用程序:
static void Main(string[] args)
{
InvokeIfNotNullOrWhitespace((inputStr) => TestMethod(inputStr), null);
InvokeIfNotNullOrWhitespace((inputStr) => TestMethod(inputStr), "");
InvokeIfNotNullOrWhitespace((inputStr) => TestMethod(inputStr), "abc");
// RESULT:
// Trying to invoke action...
// Trying to invoke action...
// Trying to invoke action...
// I have been invoked!
}
static void InvokeIfNotNullOrWhitespace(Action<string> action, string inputString)
{
Console.WriteLine("Trying to invoke action...");
if(!string.IsNullOrWhiteSpace(inputString))
action.DynamicInvoke(inputString);
}
static void TestMethod(string input)
{
Console.WriteLine("I have been invoked!");
}
我认为属性不起作用的原因是它们无法控制方法内部发生的事情。相反,"other external things" 可以查看这些属性并决定要做什么。
要实现您想要实现的目标,"external thing" 需要查看属性并决定是否执行它。这相当于我写的:统一 "check string validity" 过程的外部调用程序。
据我所知,可以使用属性完成此操作的唯一方法是使用 post sharp 和方法 interception. Alternatively if the methods are defined in an interface this can also be done by using RealProxy 之类的产品进行面向方面的编程,但似乎有点矫枉过正。
这是我的 4 美分,
- 调用属性涉及反射,已经是个坏主意了 您需要查明该属性是否已设置;
- 你在你的代码中避免了 "1 liner" 实际上是 易于输入;
- 使用方法重载;
- 您可以使用 Aspect oriented programming,它基本上会在编译时将以下示例注入您的代码中。您可以控制它与注释一起工作的方式,并且不会对生成的运行时产生负面影响。
这里有一些变化:
//1
if(string.IsNullOrEmpty(testString))
return;
//2
if(string.IsNullOrEmpty(testString) ||string.IsNullOrWhiteSpace(testString) )
return;
选择 3 时,请确保不要混合返回 null 或基于 "missing" 文本的布尔值 true/false。只有您知道您的代码应该如何流动。
也许您正在寻找方法重载 您可以通过在同一个 class 中创建两个具有相同名称的方法来做到这一点。 您可以从 MyMethod(带有字符串)调用空的 MyMethod(),这样您就不会重复逻辑。
return string.IsNullOrEmpty(testString)?MyMethod():MyMethod(testString);
你的做法其实很不错。但正如 Evk 在评论中指出的那样:您应该将 "skip checking" 提取到一个单独的方法中,尤其是在检查始终相同且需要全局更改的情况下。使用属性可以解决问题,但使用起来有点复杂。
相反,请查看下面的代码。看起来很清楚,不是吗?不要使用太多注释(也不要将它们复制粘贴到每个方法中,那是没有用的)。这样,您将获得与使用自定义属性相同的好处,但没有使用反射的丑陋之处。
public void AssertUser(UserDTO expectedUserInfo)
{
VerifyUserName(expectedUserInfo.name);
VerifyUserSurname(expectedUserInfo.surname);
VerifyUserAge(expectedUserInfo.age);
VerifyUserHeight(expectedUserInfo.height);
}
private void VerifyUserName(string name)
{
if (ShouldSkipValidation(name)) return;
// code here...
}
private void VerifyUserSurname(string surname)
{
if (ShouldSkipValidation(surname)) return;
// code here...
}
private void VerifyUserAge(string age)
{
if (ShouldSkipValidation(age)) return;
// code here...
}
private void VerifyUserHeight(string height)
{
if (ShouldSkipValidation(height)) return;
// code here...
}
// The MTM scenario does not want to validate values that satisfy the check below
private bool ShouldSkipValidation(string value)
{
return string.IsNullOrWhiteSpace(value) || value == "<>";
}