ByRef
,否则将传递ByVal
的参数。这里是有问题的实现:[ComVisible(false)]
public class ImplicitByRefParameterInspection : IInspection
{
public ImplicitByRefParameterInspection()
{
Severity = CodeInspectionSeverity.Warning;
}
public string Name { get { return "Parameter is passed ByRef implicitly"; } }
public CodeInspectionType InspectionType { get { return CodeInspectionType.CodeQualityIssues; } }
public CodeInspectionSeverity Severity { get; set; }
public IEnumerable<CodeInspectionResultBase> GetInspectionResults(SyntaxTreeNode node)
{
var procedures = node.FindAllProcedures().Where(procedure => procedure.Parameters.Any(parameter => !string.IsNullOrEmpty(parameter.Instruction.Value)));
var targets = procedures.Where(procedure => procedure.Parameters.Any(parameter => parameter.IsImplicitByRef)
&& !procedure.Instruction.Line.IsMultiline);
return targets.SelectMany(procedure => procedure.Parameters.Where(parameter => parameter.IsImplicitByRef)
.Select(parameter => new ImplicitByRefParameterInspectionResult(Name, parameter.Instruction, Severity)));
}
}
会有更好的方法吗?这是
ImplicitByRefParameterInspectionResult
类(真是个长名字!):[ComVisible(false)]
public class ImplicitByRefParameterInspectionResult : CodeInspectionResultBase
{
public ImplicitByRefParameterInspectionResult(string inspection, Instruction instruction, CodeInspectionSeverity type)
: base(inspection, instruction, type)
{
}
public override IDictionary<string, Action<VBE>> GetQuickFixes()
{
return !Handled
? new Dictionary<string, Action<VBE>>
{
{"Pass parameter by value", PassParameterByVal},
{"Pass parameter by reference explicitly", PassParameterByRef}
}
: new Dictionary<string, Action<VBE>>();
}
private void PassParameterByRef(VBE vbe)
{
if (!Instruction.Line.IsMultiline)
{
var newContent = string.Concat(ReservedKeywords.ByRef, " ", Instruction.Value);
var oldContent = Instruction.Line.Content;
var result = oldContent.Replace(Instruction.Value, newContent);
var module = vbe.FindCodeModules(Instruction.Line.ProjectName, Instruction.Line.ComponentName).First();
module.ReplaceLine(Instruction.Line.StartLineNumber, result);
Handled = true;
}
else
{
// todo: implement for multiline
throw new NotImplementedException("This method is not [yet] implemented for multiline instructions.");
}
}
private void PassParameterByVal(VBE vbe)
{
if (!Instruction.Line.IsMultiline)
{
var newContent = string.Concat(ReservedKeywords.ByVal, " ", Instruction.Value);
var oldContent = Instruction.Line.Content;
var result = oldContent.Replace(Instruction.Value, newContent);
var module = vbe.FindCodeModules(Instruction.Line.ProjectName, Instruction.Line.ComponentName).First();
module.ReplaceLine(Instruction.Line.StartLineNumber, result);
Handled = true;
}
else
{
// todo: implement for multiline
throw new NotImplementedException("This method is not yet implemented for multiline instructions.");
}
}
}
欢迎任何评论。
#1 楼
从此开始var procedures = node.FindAllProcedures().Where(procedure => procedure.Parameters.Any(parameter => !string.IsNullOrEmpty(parameter.Instruction.Value)));
var targets = procedures.Where(procedure => procedure.Parameters.Any(parameter => parameter.IsImplicitByRef)
&& !procedure.Instruction.Line.IsMultiline);
return targets.SelectMany(procedure => procedure.Parameters.Where(parameter => parameter.IsImplicitByRef)
.Select(parameter => new ImplicitByRefParameterInspectionResult(Name, parameter.Instruction, Severity)));
将其折叠为一个表达式
return node.FindAllProcedures()
.Where(procedure => procedure.Parameters.Any(parameter => !string.IsNullOrEmpty(parameter.Instruction.Value)))
.Where(procedure => procedure.Parameters.Any(parameter => parameter.IsImplicitByRef)
&& !procedure.Instruction.Line.IsMultiline)
.SelectMany(procedure => procedure.Parameters.Where(parameter => parameter.IsImplicitByRef)
.Select(parameter => new ImplicitByRefParameterInspectionResult(Name, parameter.Instruction, Severity)));
将最后一个
Select
移出SelectMany
return node.FindAllProcedures()
.Where(procedure => procedure.Parameters.Any(parameter => !string.IsNullOrEmpty(parameter.Instruction.Value)))
.Where(procedure => procedure.Parameters.Any(parameter => parameter.IsImplicitByRef)
&& !procedure.Instruction.Line.IsMultiline)
.SelectMany(procedure => procedure.Parameters)
.Where(parameter => parameter.IsImplicitByRef)
.Select(parameter => new ImplicitByRefParameterInspectionResult(Name, parameter.Instruction, Severity));
现在看来
procedure.Parameters.Any(parameter => parameter.IsImplicitByRef)
是多余的,所以让我们删除它并加入后续的Where
s return node.FindAllProcedures()
.Where(procedure => procedure.Parameters.Any(parameter => !string.IsNullOrEmpty(parameter.Instruction.Value))
&& !procedure.Instruction.Line.IsMultiline)
.SelectMany(procedure => procedure.Parameters)
.Where(parameter => parameter.IsImplicitByRef)
.Select(parameter => new ImplicitByRefParameterInspectionResult(Name, parameter.Instruction, Severity));
尚不清楚为什么需要
procedure.Parameters.Any(parameter => !string.IsNullOrEmpty(parameter.Instruction.Value))
-如果需要,则需要注释,否则我们可以只写return node.FindAllProcedures()
.Where(procedure => !procedure.Instruction.Line.IsMultiline)
.SelectMany(procedure => procedure.Parameters)
.Where(parameter => parameter.IsImplicitByRef)
.Select(parameter => new ImplicitByRefParameterInspectionResult(Name, parameter.Instruction, Severity));
哪个看起来更易于管理。或者,如果您希望使用其他语法
return from procedure in node.FindAllProcedures()
where !procedure.Instruction.Line.IsMultiline
from parameter in procedure.Parameters
where parameter.IsImplicitByRef
select new ImplicitByRefParameterInspectionResult(Name, parameter.Instruction, Severity);
#2 楼
我不知道我对这三元的感觉。public override IDictionary<string, Action<VBE>> GetQuickFixes()
{
return !Handled
? new Dictionary<string, Action<VBE>>
{
{"Pass parameter by value", PassParameterByVal},
{"Pass parameter by reference explicitly", PassParameterByRef}
}
: new Dictionary<string, Action<VBE>>();
}
我的意思是,这的确可能会更糟,而且我承认除了非常简单的任务外,我不喜欢三元组。我觉得这里需要一个
if
语句。尽管它将添加几行代码,但我认为它将增加可读性。另一方面,不是因为混乱,而是因为。做得好。我不讨厌(我是否提到我讨厌三元组?)我将如何编写它。
public override IDictionary<string, Action<VBE>> GetQuickFixes()
{
var result = new Dictionary<string, Action<VBE>>;
if (!Handled)
{
result.Add("Pass parameter by value", PassParameterByVal);
result.Add("Pass parameter by reference explicitly", PassParameterByRef);
}
return result;
}
每种方法都有其优缺点。我的方法降低了缩进的级别,但是引入了一个中间变量
Hmm ..在每个实现中三元都存在.. – Mat的杯子
我认为基类中的
GetQuickFixes
应该以字典作为参数。然后,不必在每个实现中都使用此逻辑。它只需要为未处理的案例创建适当的字典,将其传递给base,然后返回base认为必要的任何字典。这样,这种逻辑就不需要一遍又一遍地实现。您应该最终得到如下所示的内容。 public override IDictionary<string, Action<VBE>> GetQuickFixes()
{
var fixes = new Dictionary<string, Action<VBE>>
{
{"Pass parameter by value", PassParameterByVal},
{"Pass parameter by reference explicitly", PassParameterByRef}
}
return base.GetQuickFixes(fixes);
}
现在三元数在基类中变得可以接受。
public IDictionary<string, Action<VBE>> GetQuickFixes(IDictionary<string, Action<VBE>> actions)
{
return !Handled ? actions : new Dictionary<string, Action<VBE>>();
}
评论
\ $ \ begingroup \ $
嗯..每种实现中都有三元组。
\ $ \ endgroup \ $
– Mathieu Guindon♦
2014年12月18日,0:25
\ $ \ begingroup \ $
老实说,还不错。只是一个小问题,我相信对于每个同意我的人,都会有两个不同意。
\ $ \ endgroup \ $
–RubberDuck
2014年12月18日下午0:26
\ $ \ begingroup \ $
我个人会重新排列三元组,但将其保留为三元组,因为您知道这是一把锤子。
\ $ \ endgroup \ $
–马拉奇♦
2014年12月18日下午4:16
\ $ \ begingroup \ $
我喜欢这个它仅创建一次返回值。
\ $ \ endgroup \ $
– Mathieu Guindon♦
2014年12月18日下午4:27
\ $ \ begingroup \ $
好的。我认为上次编辑。有另一个想法。让我感到困扰的是,每个实现中都有相同的逻辑。
\ $ \ endgroup \ $
–RubberDuck
2014年12月18日下午4:59
#3 楼
public override IDictionary<string, Action<VBE>> GetQuickFixes()
{
return !Handled
? new Dictionary<string, Action<VBE>>
{
{"Pass parameter by value", PassParameterByVal},
{"Pass parameter by reference explicitly", PassParameterByRef}
}
: new Dictionary<string, Action<VBE>>();
}
这样我就可以解决这个问题,以便我可以使用
Handled
而不是不处理...
所以看起来像这样
public override IDictionary<string, Action<VBE>> GetQuickFixes()
{
return Handled
? new Dictionary<string, Action<VBE>>()
: new Dictionary<string, Action<VBE>>
{
{"Pass parameter by value", PassParameterByVal},
{"Pass parameter by reference explicitly", PassParameterByRef}
};
}
#4 楼
var newContent = string.Concat(ReservedKeywords.ByVal, " ", Instruction.Value);
这是我最近学到的一个很妙的东西:
var newContent = ReservedKeywords.ByVal + " " + Instruction.Value;
将被编译器优化为致电
string.Concat
,与上述完全相同。它也更具可读性,因此您不会有任何损失。您可以在Eric Lippert的博客上了解有关它的更多信息。方法
PassParameterByRef
和PassParameterByVal
相同,除了一个变量外,并且可以(除非您打算更改它们)常见的方法。#5 楼
我不确定Severity
是public set
的事实。作为您代码的客户端,我是谁说ImplicitByRefParameterInspection
的严重性为X,而您作为了解他的知识的开发人员说它的严重性为Warning
。我认为您界面应该只暴露
CodeInspectionSeverity Severity
上的吸气剂。我不是项目的一部分,但是我很难看清要
set
的严重性的情况。由于它是一种抽象,因此您无法确定它的严重性。(我认为)您想设置
IInspection
的实现的严重性。如果我将其转换为代码,如下所示:
public interface IInspection
{
CodeInspectionSeverity Severity { get; }
}
[ComVisible(false)]
public class ImplicitByRefParameterInspection : IInspection
{
public ImplicitByRefParameterInspection()
{
Severity = CodeInspectionSeverity.Warning;
}
public CodeInspectionSeverity Severity { get; private set; }
}
这样,我(作为客户)可以知道检查的严重性,但是我无法
IInspection
,这是一件好事,因为我完全不知道应该是什么。评论
\ $ \ begingroup \ $
我应该在该帖子中包含该枚举。.它从DoNotShow变为Error-打算由使用它的开发人员进行配置-如果您想将检查类型显示为“提示”,则为“建议”或“警告”,或者如果您不想看到它,则可以进行配置。用户(VBA / COM)没有看到该类型,因此无法以编程方式访问它。
\ $ \ endgroup \ $
– Mathieu Guindon♦
2014年12月18日15:30
\ $ \ begingroup \ $
+1因为您的回答在上下文中是有意义的,但实际上有一种配置可以让用户指定严重性级别。]
\ $ \ endgroup \ $
–RubberDuck
2014-12-18 15:30
\ $ \ begingroup \ $
目前还不确定我是否写了答案,但是我认为它仍然很有用! :)
\ $ \ endgroup \ $
–IEatBagels
2014年12月18日15:33
评论
检查是否在您的控制之下?并且是代码检查的严重程度{get;组; }接口的一部分?@TopinFrassi是的,是的:)