[No0000B1]ReSharper操作指南2/16-ReSharper食谱与特定于域的教程

自动导入名称空间

有关更多信息,请参阅导入缺少命名空间

每当您使用未添加using语句的命名空间中的类型时,ReSharper会为您提供在您所在文件的顶部添加相应的语句。这由在所使用的类型上方显示的蓝色框表示。要添加相应的参考,只需按Alt+Enter

上面假设你所在的项目实际上引用了相应的DLL。如果没有,ReSharper仍然可以帮助您添加DLL引用和using语句,前提是您的解决方案中的某个其他项目引用了必要的DLL,并且您所在的项目引用了该项目。

如果发生这种情况,您将无法获得蓝色弹出窗口。相反,正在使用的类型将以红色突出显示,并且ReSharper将为您提供快速修复以添加对相应程序集的引用:

选择最上面的选项将添加对System.Windows.Forms当前项目的引用,并usingSystem.Windows.Forms;在文件顶部添加一条语句。

创建一个装饰器

有关装饰者模式的更多信息,请查看这篇维基百科文章

装饰器设计模式用于动态地向对象添加其他行为。另外,通过使用接口,可以使用装饰器以类似于多继承的方式统一类型。

让我们看一个例子-假设你有两个对象,叫BirdLizard,要放入装饰:

classBird

{

publicvoidFly()

{

...

}

}

classLizard

{

publicvoidWalk()

{

...

}

}

1.通过提取接口重构获取对象接口

由于装饰器不能从这两个类继承,所以我们可以从这个菜单的Refactor()中为这两个对象调用ExtractInterface重构,以获得它们的接口:Ctrl+Shift+R

调用这个重构会弹出一个窗口,询问我们哪些成员应该出现在界面中:

在我们为这两个类做了这些之后,我们最终得到下面的代码:

internalinterfaceIBird

{

voidFly();

}

classBird:IBird

{

publicvoidFly()

{

...

}

}

internalinterfaceILizard

{

voidWalk();

}

classLizard:ILizard

{

publicvoidWalk()

{

...

}

}

2.声明一个装饰器类

有了这些接口,我们可以制作一个装饰器。首先,我们声明一个叫做的类Dragon,表明它实现了两者IBird并且ILizard

classDragon:IBird,ILizard

{

...

}

现在是聚合成员。最简单的做法是先将它们都声明为字段,即:

classDragon:IBird,ILizard

{

privateBirdbird;

privateLizardlizard;

}

3.使用快速修复来初始化未使用的字段

现在,我们可以对未使用的字段应用快速修复,并从构造函数参数中初始化它们两个:

在此之后,我们的班级将如下所示:

classDragon:IBird,ILizard

{

privateBirdbird;

privateLizardlizard;

publicDragon(Birdbird,Lizardlizard)

{

this.bird=bird;

this.lizard=lizard;

}

}

4.为源对象生成委派成员。

现在为了最后的结果-我们希望为鸟和蜥蜴产生委派成员。这很简单-我们只需打开Generate菜单(Alt+Insert)并选择DelegatingMembers

ReSharper然后问我们需要委派哪些成员:

最终的结果是:

classDragon:IBird,ILizard

{

publicvoidFly()

{

bird.Fly();

}

publicvoidWalk()

{

lizard.Walk();

}

privateBirdbird;

privateLizardlizard;

publicDragon(Birdbird,Lizardlizard)

{

this.bird=bird;

this.lizard=lizard;

}

}

而已!我们的装饰者准备好了。

处理资源文件中的很多条目

在资源文件中管理大量数据可能很困难,但ReSharper会尽力帮助您处理本地化数据。首先您会注意到文件结构窗口中.resx文件的支持,该文件显示了一个方便的字符串标识符列表及其内容:

ReSharper还包含代码检查功能,可以帮助您识别资源条目的问题-例如,在您忘记在默认文化中声明资源的情况下:

ReSharper导航功能非常适合资源,让您可以导航到declarationF12)或usagesShift+Alt+F12),以在文化中性,特定于文化的资源文件和源代码中的资源使用之间移动。此外,您可以使用动作指示符)在不同文化的资源定义之间跳转:

使用ReSharperTeamCity检测构建中的代码问题

你知道你可以在TeamCity服务器上运行ReSharper代码检查吗?事实上,很久以前我们在TeamCity中增加了对此功能的支持,但似乎该功能并未广泛知晓,特别是ReSharper用户。该设置本身非常简单,我们将通过它,并在混合中额外添加一些好东西。

在此基础上,TeamCity使用InspectCode进行代码检查,并使用dupFinder进行重复分析。如有必要,可以在任何CI或构建服务器上使用这些免费的命令行工具。

要开始使用TeamCity,请学习TeamCity文档

TeamCity中激活.NET Inspections

ReSharper检查添加到构建过程仅仅是添加名为Inspections.NET)的构建步骤。唯一需要的参数是VisualStudio解决方案文件

如果我们不指定Custom settings profile path,自定义设置配置文件路径,TeamCity将采用代码检查的默认设置。但是,我们可以配置这些以匹配我们自己/团队的标准。这是在 Code Inspection | Inspection Severity "检查严重性"页面。我们可以改变任何检查的严重性,例如,使用以下方法String.IsNullOrEmpty

...并将设置保存到解决方案团队共享层。然后将设置保存在名为{Solution}.sln.DotSettings的文件中,该文件通常会签入到源代码控制中,以便在VisualStudio中打开解决方案时自动应用于其他团队成员。我们可以使用这个相同的设置文件来指示TeamCity的自定义检查设置:

分析结果

当构建步骤运行时,TeamCity会生成一个可导航的报告,供我们分析检查结果

复选框仅检查新问题仅用于突出显示自上次构建运行以来仅出现的新问题。括号内的数字+1-1是自上次运行以来的差异。

我们可以浏览整个项目或特定命名空间的检查。检查按类别,问题类型和右侧窗格中的相应文件进行分组。我们甚至可以通过点击行号导航到实际的文件。为此,我们需要安装VisualStudio,并安装VisualStudioTeamCity插件(如果不这样做,单击链接将提示您使用对话框下载并安装加载项)。

根据检验严重程度采取行动

在服务器端添加检查的主要好处之一是将代码质量保持在一定水平,从而我们可以让构建过程根据一系列条件采取行动。例如,如果检测到太多警告或错误,我们可能希望构建失败。

"项目配置"窗口中的"构建失败条件"下,我们可以添加新的构建失败条件:

我们选择基于度量更改的失败构建,然后根据警告或错误指出我们是否希望构建失败。在我们的例子中,我们要选择错误,如果有多个错误,就会失败。

很显然,如果我们希望检查对我们构建的状态产生影响,也就是说构建失败,我们只能根据警告或错误进行构建。因此,提示和建议不能使用。因此,在ReSharper中配置检查严重性时,我们应该考虑到这一点。

如果我们现在再次运行我们的构建,它应该失败,因为错误的数量大于1。下面是相同输入和检查的输出,但是一个运行在构建失败条件下,另一个没有它。

检查复制/粘贴代码

尽管严格来说,这与ReSharper功能无关,但由于我们在构建过程中讨论了代码质量,因此提及TeamCity可以检查代码重复是有意义的。

和以前一样,激活代码重复仅仅是添加一个新的构建步骤,即重复查找器(.NET)。我们可以指定要忽略的文件夹,无论我们是否要考虑命名空间,类型名称以及其他一些选项。

输出结果是一个格式良好的导航屏幕,可以让我们浏览不同的文件,并查看TeamCity检测到的重复内容(下面调整了空间限制):

正如所料,如果我们有太多的代码重复,我们也可能会失败

概要

使用JetBrains工具,向构建过程添加代码质量检测功能并且在构建过程中出现构建失败时,如果不应该出现在生产代码中,则会非常简单。

检测可能的NullReferenceExceptions

空检查是.NET开发中最常见的操作之一。ReSharper是一个通过为使用可能为null的实体的开发人员提供特殊支持而严肃对待空值检查的工具。

ReSharper的第一件事是检测NullReferenceException发生的可能性。例如,假设我们尝试访问XML属性的值而不检查它是否存在,

varxe=XElement.Parse("<test/>");

varattrib=xe.Attribute("a");

varvalue=attrib.Value;

由于以Value这种方式访问并不是非常安全,因此ReSharper强调这一点,并将鼠标移动到该位置显示以下弹出窗口。

将脱字符放在标识符上并按下,Alt+Enter会显示一个快速修复程序,允许您自动对变量执行空检查:

大部分由ReSharper完成的空检查都是通过代码注释实现的,这些注释有两种工作方式:

首先,我们注释了.NETFCL中的大量符号以及包含ReSharper安装中包含外部注释的属性的NUnit。例如,Attribute上面例子中的方法用这种方式注释CanBeNullAttribute

以下是外部注释方法的另一个示例:如果我们尝试Uri使用null参数创建一个,我们会得到以下弹出消息:

当然,没有什么能阻止你在你自己的代码中使用这些属性。有几种方法可以将这些属性添加到您的项目中:

  • 推荐的方法是在程序集中安装NuGetJetBrains.Annotations
    实际上,你甚至不需要到NuGet网站去获取软件包。只需添加usingJetBrains.Annotations;指令,并使用相应的操作来自动获取软件包。
  • 您可以简单地将项目引用添加JetBrains.Annotations.dll,您可以在ReSharper安装目录中找到它。
  • 您还可以使用默认名称空间或任何其他名称空间在您的项目中的任何位置嵌入属性声明JetBrains.Annotations

    现在,您可以使用这些属性修饰您自己的方法参数,ReSharper将会选择它们:

    获得有关迁移到新C#功能的帮助

    要了解有关ReSharper支持的C#6.0功能的更多信息,请查看此博客文章

    随着C#的新版本问世,想要更新代码以利用最新的语法功能是很自然的。幸运的是,ReSharper可以帮助您自动更新您的代码。

    默认情况下,ReSharper根据关联的编译器自动检测C#版本。但是,您可以通过在解决方案资源管理器中选择项目并在VisualStudio的"属性"窗口中使用C#语言级别属性(选择菜单中的查看|属性窗口)来显式指定目标C#版本。

    让我们以C6.0最受欢迎的功能之一-条件访问表达式为例。首先要注意的是,ReSharper在编辑器中轻轻点出了使用新语言功能的可能性:

    像往常一样,按下Alt+Enter突出显示的代码可以快速修复,帮助您使用新的语言功能:

    应用修复程序后,该方法转换如下:

    publicintGetNickNameLength(Personperson)

    {

    returnperson?.Nickname.Length??0;

    }

    这里要记住的重要一点是,如果您不喜欢某些新的语言功能,您可以轻松告诉ReSharper不要打扰您

    当然,您可以在所需的范围内找到语言使用机会直至整个解决方案:

    另外,您可以使用范围修复功能在整个项目中一次性实施一些新的语言功能:

    ......或者在整个解决方案中:

    建立自动代码审查

    使用ReSharper,代码审查其实很简单。毕竟,显示错误和可能的改进以及其他问题的检查标记无处不在,很难错过。

    但是,如果您想一次检查所有问题,还有一种方法可以实现ReSharper | Inspect | Code Issues in Solution/Project中的代码问题。这将向您显示一棵树,按类型对问题进行分组,并让您向下钻取特定实例:

    请记住,每个ReSharper代码检查可以ReSharper选项对话框中配置,并且可以使用ReSharper的分层设置轻松共享首选项,所得到的结果实际上是一个自动代码审查过程。

    找到死亡的.NET代码

    使用ReSharper的一个好处是,它显示了你自己的代码,你不使用的位。ReSharper实际上非常聪明:它不仅能够指出任何地方都没有使用的代码,还能够检测到更复杂的情况-例如一个字段被声明和初始化的情况,但实际上除了初始化之外没有任何东西到它。

    我们来看一个例子。假设我们有一个类Person定义如下:

    publicclassPerson

    {

    privatestring_name;

    publicPerson(stringname)

    {

    this._name=name;

    }

    }

    现在,ReSharper会指出该_name字段未被使用。如果您将鼠标指针悬停在此字段上,您将收到以下消息:

    如果您现在按下Alt+Enter_name字段,ReSharper将提供一个选项来删除姓名字段及其任何分配:

    结果如下:

    注意现在ReSharper告诉我们该参数也可以被删除。我们使用相应的快速修复

    我们得到一个空的构造函数,正如您可能已经猜到的那样,它也不是必需的,因为缺省构造函数是默认实现的。再一次,ReSharper接受它并为我们提供了一个摆脱构造函数的选项:

    修复不一致的命名空间命名

    使用ReSharper的一个好处是,它显示了你自己的代码,你不使用的位。ReSharper实际上非常聪明:它不仅能够指出任何地方都没有使用的代码,还能够检测到更复杂的情况-例如一个字段被声明和初始化的情况,但实际上除了初始化之外没有任何东西到它。

    但是,如果您有多个文件的命名空间不正确,请逐一浏览它们可能会很痛苦。幸运的是,您只需按下Ctrl+Shift+R解决方案资源管理器中的节点并选择调整命名空间

    这将弹出一个对话框,让您选择需要调整名称空间的所有文件:

    选择要修复的名称空间之后,它们将被调整为其预期值(取决于项目设置和文件位置)。

    检查整个解决方案是否符合命名风格

    有关ReSharper命名样式功能的详细说明,请参阅命名样式主题。

    如果您希望代码库使用一致的命名风格,则可以使用ReSharper配置首选项,然后搜索代码中命名规则被破坏的所有位置。

    首先,打开ReSharper选项对话框,并导航到相应语言下的命名样式页面。

    这是您可以重新定义特定元素的命名规则的地方。只需单击编辑即可更改特定代码元素的默认值:

    完成后,关闭选项对话框并选择 ReSharper | Inspect | Code Issues in Solution/Project以查找所有代码问题。您将看到代码中所有问题的分类树。在这里,只需找到Constraint Violations约束违规部分,您就会看到分析范围内的命名不匹配列表:

    双击其中的每一个都会将您带到发生问题的代码行。当然,ReSharper可以帮助您调整相应标识符的名称,甚至是在特定范围内调整所有命名风格违规的名称:

    一次将类移入单独的文件

    有关更多信息,请参阅将类型移入匹配文件重构。

    您可能已经看到ReSharper为您提供了将类型转换为相应文件的选项。但是您是否知道可以一次将多种类型转换为相应命名的文件?例如,假设你有一个带有类型的文件AppleOrange并且Plum定义如下:

    Namespace MyLibrary

    {

    Public class Apple

    {

    }

    Public class Orange

    {

    }

    Public class Plum

    {

    }

    }

    我能做些什么来分离这些是Ctrl+Shift+R在解决方案资源管理器中按下包含的项目,然后选择将类型移动到匹配文件中

    然后ReSharper询问哪些元素应该被移动到单独的文件中:

    一旦你按下Next,这些类型将被分成相应的命名文件:

    快速创建一个类型

    在本教程中,我们使用一组标准方法创建一个类型。

    C#中创建类型或实体可能非常困难。毕竟,我们中有多少人记得正确实施Equals()?幸运的是,ReSharper会帮助你。让我们来看看。

    首先,我们定义一个最简单的实体类Person,它将存储一个人的姓名和年龄:

    Public class Person

    {

    Public string Name{get;set;}

    Public int Age{get;set;}

    }

    1.生成构造函数

    就目前而言,这个类的初始化是痛苦的,因为它没有构造函数。让我们通过使用生成代码命令(Alt+Insert)来创建一个。首先,让我们在课堂上点燃它并选择构造函数:

    现在,我们会看到一个对话框,询问我们要初始化哪些属性。我们来挑选它们。

    在按下完成之后,我们的类以生成的构造函数结束:

    publicPerson(stringname,intage)

    {

    Name=name;

    Age=age;

    }

    2.生成相等成员

    假设我们想要将Person实例保存在一个HashSet<Person>集合中。为此,我们需要实施Equals()GetHashCode()ReSharper再次帮助我们-我们再次调用Generate命令,并选择Equality成员。出现以下对话框:

    选择生成相等运算符(==!=)以及IEquatable<T>ReSharper的实现的选项将生成以下代码:

    Public bool Equals(Person other)

    {

    if(ReferenceEquals(null,other))return false;

    if(ReferenceEquals(this,other))return true;

    return string.Equals(Name,other.Name)&&Age==other.Age;

    }

     

    Public override bool Equals(object obj)

    {

    if(ReferenceEquals(null,obj))return false;

    if(ReferenceEquals(this,obj))return true;

    if(obj.GetType()!=this.GetType())return false;

    return Equals((Person)obj);

    }

     

    Public override int GetHashCode()

    {

    unchecked

    {

    return((Name!=null?Name.GetHashCode():0)*397)^Age;

    }

    }

     

    Public static bool operator==(Personleft,Personright)

    {

    Return Equals(left,right);

    }

     

    Public static bool operator!=(Personleft,Personright)

    {

    Return !Equals(left,right);

    }

    3.生成格式化成员

    现在,我们还想获得ToString()一些日志记录和调试方法的实现。再次,Generate菜单在这里。我们只需从菜单中选择格式化成员,挑选我们想要显示的属性ToString(),然后-ReSharper生成以下实现:

    Public override string ToString()

    {

    Return string.Format("Name:{0},Age:{1}",Name,Age)

    }

    快速国际化.NET应用程序

    假设您想快速将多语言支持添加到您的应用程序,但不想开始搞乱RESX文件。事实上,有一种更简单的方法。给出以下代码:

    try

    {

    Double tax=CalculateTax();

    }

    catch(TaxExceptione)

    {

    MessageBox.Show("Cannot calculate tax");

    }

    要将字符串移动到资源中,请将字符移到字符串上,打开RefactorThis菜单(Ctrl+Shift+R)并选择MovetoResource

    现在,如果你没有资源文件,ReSharper会警告你:

    但是,制作一个很容易:

    现在,如果您尝试将字符串移到资源中ReSharper会注意到新创建的RESX文件并提供将字符串放入其中:

    一旦接受上述设置,字符串将被移动到资源文件中:

    <dataname="Tax_Main_Cannot_calculate_tax"xml:space="preserve">

    <value>Cannotcalculatetax</value>

    </data>

    而且,当然,您的代码将被更改为使用资源字符串:

    try

    {

    Double tax=CalculateTax();

    }

    catch(TaxExceptione)

    {

    MessageBox.Show(Resource1.Tax_Main_Cannot_calculate_tax);

    }

    快速介绍使用语句并尝试...catch

    假设您想快速将多语言支持添加到您的应用程序,但不想开始搞乱RESX文件。事实上,有一种更简单的方法。给出以下代码:使用实时模板生成代码块ReSharper还可以让您使用其他语句(例如try...catchusing语句)来包围现有代码

    要显示环绕菜单,只需选择代码块并按Ctrl+E,U。这会弹出一个可用的环境声明菜单:

    现在,您可以开始输入模板名称。例如,要围绕选择using,您可以us...在弹出窗口打开时开始输入。ReSharper将生成默认代码存根并允许您为模板参数提供值:

    降低算法复杂度并提升模块性

    几乎每个开发人员都发现自己处于一种单一的,几乎不可读的方法中的复杂算法的情况,该方法与其他方法在一个类中纠缠在一起。例如,假设你有一个用于求解方程的通用类:

    Public class EquationSolvers

    {

    Public static Tuple<double,double>Quadratic(doublea,doubleb,doublec)

    {

    Double disc=b*b-4*a*c;

    if(disc<0)

    throw new ArgumentException("Cannotsolveequationwithcomplexroots");

    double sqrt=Math.Sqrt(disc);

    return new Tuple<double,double>(

    (-b+sqrt)/(2*a),(-b-sqrt)/(2*a));

    }

     

    //othersolvershere

    }

    上面的方程求解器是硬编码的,这意味着要替换不同的求解器,您必须手动替换每个实例。我们先把它分成一个单独的class。为此,我们使用MovetoAnotherType重构Ctrl+R,O):

    然后,我们需要指定类来移动方法。为了更好地分离问题,我们选择了一个单独的课程QuadraticEquationSolver

    现在这个方法已经被移动了,让我们尝试将判别式分别计算出来。这很简单-我们只需选择判别式计算并调用ExtractMethod重构Ctrl+R,M):

    现在,我们需要做的就是给这个新方法一个名字:

    它完成了:

    Private static double CalculateDiscriminant(doublea,doubleb,doublec)

    {

    Return b*b-4*a*c;

    }

    现在,让我们假设,过了一段时间,我们找到了一个更安全的二次方程求解器。为了将它分解到程序中,我们首先需要创建一个抽象基类QuadraticEquationSolverBase。我们使用RefactorThis菜单()中提供的ExtractSuperclass重构重构:Ctrl+Shift+R

    在出现的对话框中,我们可以选择向上推广哪些成员。我们只想要这个CalculateDiscriminant方法:

    我们添加一个Calculate()方法的抽象定义(以前称为Quadratic())并最终得到以下基类:

    Public abstract class QuadraticEquationSolverBase

    {

    Protected double CalculateDiscriminant(doublea,doubleb,doublec)

    {

    Return b*b-4*a*c;

    }

    Public abstract Tuple<double,double> Calculate(doublea,doubleb,doublec);

    }

    我们还摆脱了static任何关键字,假设这些实现QuadraticEquationSolverBase将由我们的代码中的终身管理器来处理。因此,ReSharper提醒我们将override关键字添加到Calculate我们的QuadraticEquationSolver类中的重命名方法中:

    现在,假设我们找到了更安全的二次方程求解器。让我们来实现它。首先,我们在基类中使用Create派生类型上下文操作

    然后,我们被要求实现这种类型的成员,我们这样做:

    最后,我们提供一个实现,利用基类的CalculateDiscriminant()方法:

    Class SafeQuadraticEquationSolver:QuadraticEquationSolverBase

    {

    Public override Tuple<double,double> Calculate(doublea,doubleb,doublec)

    {

    Double disc=CalculateDiscriminant(a,b,c);

    if(disc<0)

    throw new ArgumentException("Cannotsolveequationwithcomplexroots");

    double q=-0.5*(b+Math.Sign(b)*disc);

    return new Tuple<double,double>(q/a,c/q);

    }

    }

    我们完成了!现在,二次方程求解器可以很容易地使用,其配置和实例通常由IoC容器处理。

    在没有复制粘贴的情况下重新订购代码

    有关详细信息,请参阅重新排列代码元素

    你有没有想过重新对代码成员进行重新排序-比如说,在一个类中的成员或者只是成员语句-没有通常的复制粘贴例程?用ReSharper,这很容易。

    这里要记住的捷径是Ctrl+Shift+Alt+箭头按钮。在按住Ctrl+Shift+Alt组合键的同时,箭头键具有多种用途,具体取决于代码中插入符号的位置以及您选择的代码块。这里有些例子:

  • a+b如果可能,在添加操作的成员上按左右箭头键将向左或向右移动操作数。例如,在光标打开的情况下b,按Ctrl+Shift+Alt+Left会将表达式更改为b+a
  • 按向上和向下箭头键上下移动整个语句。注意:如果你想拥有一份声明中移动内部跟随它,只需使用左/右按键,而不是向上/向下的代码块。
  • 在方法声明中使用插入符号时,向上/向下键(与Ctrl+Shift+Alt当然一起)相对于其他成员声明向上和向下移动它。这使您可以按照自己的意愿对字段,属性,方法和事件进行重新排序。

    现在这个方法已经被移动了,让我们尝试将判别式分别计算出来。这很简单-我们只需选择判别式计算并调用扩大和缩小选择Ctrl+Alt+Right):Ctrl+Alt+Left签约。

    检查项目之间的依赖关系

    使用ReSharper,在解决方案中找到不同项目之间的依赖关系很容易。要找到哪个代码依赖于特定的模块,只需在解决方案资源管理器中右键单击该项目或引用的程序集,然后从菜单中选择Find Code Dependent on Module查找代码依赖于模块

    这将向您显示一个树,其中包含引用该模块的文件中的项目,单个文件和行。

    您也可以在相反方向导航以查找由特定项目或其他项目引用的代码-在解决方案资源管理器的相同上下文菜单中选择Find Symbols External to Scope在范围外查找符号。这将找到您引用的所有项目和程序集:

    正如你所看到的,这也可以让你深入了解你正在使用的引用代码。

    如果解决方案中有很多项目,则可视化项目依赖关系图可能最有帮助。要显示它,请在SolutionExplorer上下文菜单中选择ShowProjectDependencyDiagram

    简化对象创建

    你有没有发现自己处于一直在扩大你的class的情况下,增加越来越多的构造函数以及它们自己的配置细节?你有没有希望能够将对象创建代码取出到一个单独的类中,并将其重新组织成更具可读性?

    让我们来看看"重构为模式"书籍中的一个场景。在这里,我们有几个贷款构造函数都隐藏了参数的真实意图:

    Public class Loan

    {

    Public Loan(double commitment,int riskRating,int maturity)

    {

    //implementationomitted

    }

    Public Loan(double commitment,int riskRating,int maturity,DateTime expiry)

    {

    //implementationomitted

    }

    Public Loan(double commitment,double outstanding,int riskRating,int maturity,DateTime expiry)

    {

    //implementationomitted

    }

    }

    现在,让我们将这些构造函数重构为工厂方法。为此,我们依次使用每个构造函数,并使用"重构"菜单()中的"使用FactoryMethod重构替换构造函数"进行重构Ctrl+Shift+R

    因此,我们可以给新的工厂方法一个名称,但我们也可以指定一个不同的类来放置工厂方法。

    你最终得到的是LoanFactory该类中的工厂方法:

    Public class LoanFactory

    {

    Public static LoanCreateTermLoan(doublecommitment,intriskRating,intmaturity)

    {

    Return new Loan(commitment,riskRating,maturity);

    }

    }

    为所有相关的构造函数做这件事将产生一个完整的工厂类。请注意,如果您将工厂方法放入原始类(例如,Loan),则相应的构造函数将变为私有。但是,由于我们将这些构造函数转换为单独的工厂类,构造函数仍然是公共的。

    当您调用它时,请列出一大堆可能的方法签名

    有关更多信息,请参阅参数信息

    您可能已经看到包含如此多重载的构造函数和方法,因此很难使其中的某个人称呼它的头或尾。ReSharper试图通过其类似于IntelliSense的扩展功能来帮助您。

    要查看包含参数信息的列表,只需照常输入方法,或按Ctrl+Shift+Space。这会显示如下菜单:

    使用向上和向下键在不同的方法/构造函数签名之间导航。根据您在声明中的位置,ReSharper会向您显示您当前输入参数的参数信息。例如:

    正如你在上面的例子中看到的那样,一些参数选项已经变灰了,因为输入字符串类型的第一个参数使它们不适用。

    加快创建单元测试

    单元测试是必不可少的,但它们也非常冗长-每个测试装置都需要一个正确装饰的类,每个测试用例-它自己的方法。此外,你可能会发现自己打字的Assert.Equals次数太多了。

    我们来看看是否可以缩短使用ReSharper代码模板创建单元测试所需的时间。我们将首先创建一个文件模板,这是ReSharper一次创建整个文件的一种方式。首先,让我们开启ReSharper | Tools | Templates Explorer...菜单项。我们会看到以下内容:

    按下NewTemplate按钮,我们可以为测试夹具定义一个完整的模板。你可以使用具体的类型和实现,但是我们将遵循下面的一般NUnit约定:

    现在,如果我们想使用此模板创建单元测试夹具,我们可以右键单击一个项目并选择Add | New from Template | More。我们会看到下面的对话框:

    我们可以在这里选择我们的'测试夹具',另外勾选'添加到快速列表',这样为模板添加了所有C#项目的快速访问列表,并且我们从模板新建New from Template而不选择更多

    在对话框中单击确定将创建以下文件:

    Namespace MyProject

    {

    [TestFixture]

    Public class MyFixture

    {

    [Test]

    Public void MyTest()

    {

     

    }

    }

    }

    这些属性当然可以根据您的首选单元测试框架进行定制。

    现在,我们来看看测试方法。通常,这些是没有参数的void方法(参数化测试是一种'特殊情况'),并Test附加了属性。

    为此,我们切换到模板浏览器窗口实时模板选项卡。我们再一次简单地为一个方法定义一个存根,并将其作为方法名称的一个变量,并指出插入模板一旦模板扩展到哪里。$NAME$$END$

    现在,test在我们的测试夹具内部打字并按下,就会Tab产生一种新的测试方法。

    我们可以做的另一件事是为其创建一个活动模板Assert.IsEqual()。这也很简单:我们只需使用两个参数定义一个活动模板:

    这两个都使用ConstantValue宏。这并不是必须的,但它可以对代码进行优化,并在需要实际使用的时候使模板更易于理解。

    所以你有它-测试夹具文件模板和测试AE模板,您可以快速,轻松地生成测试代码存根。随意为其他测试相关的元素使用相同的方法,例如使用安装/拆卸方法生成测试装置,使用文件生成作为活动模板而不是文件模板(请记住,您始终可以将类移至一个单独的文件),为其他类型的断言创建实时模板等。祝你好运!

    查看.NETFramework源代码

    因此,您正在使用.NET框架对象,并且您很想知道在框架中定义的方法内会发生什么。你怎么做呢?那么,使用ReSharper,其实很简单。

    首先,Ctrl点击你想查看的元素(比如说MessageBox.Show)。您第一次执行此操作时,会弹出以下对话框:

    如果选择转到.NETFramework选项,ReSharper将尝试下载与您感兴趣的类相关的程序集的源代码和PDB

    一旦完成,您需要接受EULA,就是这样-您将看到实际的.NETFramework源代码:

    适用于UniversalAppsWindowsPhoneReSharper

    就像SilverlightWPF平台的开发一样,通用应用程序和WindowsPhone的开发涉及到与两种类型的文件交互-定义用户界面的XAML文件和用作代码隐藏的C#文件,并定义了什么发生在应用程序中。ReSharper不仅简化了对这些文件的编辑,而且还提供了同时更改XAML和代码隐藏的功能。

    基本的XML特定功能

    值得指出的第一件事是,由于ReSharper支持XMLXAML,因此ReSharper提供了许多用于编辑XAML文件的功能。因此,对于元素的插入符号,您将看到以下上下文操作

    让我们简单谈谈它们的作用:

  • Remove tag and promote children移除标签本身,但其所有内容都会缩进并移至已移除标签的级别。
  • Replace tag替换标签可让您使用不同的元素更改标签的类型-例如,更改Bordermy:SpecialBorder
  • Replace all tags 为与上述相同,但所有内部定义Border也将被更改。这意味着如果你有一个BorderaBorder,你最终会得到my:SpecialBorder一个my:SpecialBorder

    ReSharper知道如何展开和折叠空白元素。封闭的元素提供了扩展选项,以便您可以在其中添加一些子元素:

    而展开的空标签可以折叠:

    也可以将一个属性提升为嵌套元素:

    当然,反向操作也是可用的:

    除了上述上下文操作外,ReSharper还允许您重新排列XML元素和属性。通过按住Ctrl+Shift+Alt,您可以按左右箭头键在元素内移动属性;保持相同的组合,并按下向上和向下键将包含元素中的整个元素(包括其属性和子元素)向上和向下移动:

    文件结构

    就像普通的代码文件一样,ReSharper文件结构窗口Ctrl+Alt+F)能够显示XAML文件的结构。您也可以通过此窗口导航到您在树中选择的元素。

    资源

    资源是XAML开发中的核心概念,ReSharper可以帮助您在XAML代码中正确创建资源。例如,如果您使用(仍然)不存在的资源创建资源字典,则ReSharper会为您提供用于根据用法生成此资源的选项:

    这里有两个选项:

  • 创建类型Create type创建一个简单的CLR类型
  • 创建XAML类型Create XAML type创建一个自定义XAML控件

    无论您选择哪个选项,资源都将在正确的名称空间中创建,如果它已经注册在顶级元素中。

    除了创建资源之外,ReSharper还提供销毁选项-例如,在不使用资源的情况下:

    就地重构和导航

    就像使用普通代码一样,ReSharper就地重构功能Ctrl+Shift+R)在XAML中可用。例如,如果您在XAML中使用自定义控件类,则可以像访问.cs文件中的类定义一样访问相同的重构选项:

    值得注意的是,一些重构功能可用于特定于XAML的元素。例如,您可以对静态资源键执行重命名

    同样,您可以使用NavigateToAlt+`)菜单从特定符号进行导航:

    值得注意的是,重构和导航菜单在"文件结构"窗口"解决方案资源管理器"中都可用。

    实时模板

    ReSharper附带以下XML特定的实时模板

  • TC模板创建了一个封闭的标记像<ThisOne/>
  • T模板创建一个开放的标签一样<ThisOne></ThisOne>
  • a模板创建类似的属性thisOne=""

    当然,没有什么能阻止你定义你自己的XML专用模板。您甚至可以通过在模板范围中指定*.xaml文件扩展名将它们限制为XAML文件。

    用于数据访问的ReSharper

    无论您使用哪种数据库和驱动程序/ORM,在您的应用程序中设置数据访问的任务都非常相似。从创建实体到设置存储库,ReSharper都可以帮助您更好,更快地完成工作。

    实体创建

    实体是处理数据访问的核心,因为它们存储数据库中的数据。有很多方法可以在ReSharper中快速创建实体。一种方法是使用Alt+Insert解决方案资源管理器中的快捷方式,它将为您提供熟悉的生成菜单以及可用文件模板的列表:

    在上面的菜单中选择Class,系统会提示您为该课程命名:

    你会自动获得一个Person名为Person.cs的文件。

    作为替代,您可以让ReSharper根据用法推断类名称及其成员。例如,您可以键入一个类的调用,然后按Alt+Enter生成该类:

    用同样的方式,ReSharper可以帮助您生成班级成员。例如,您可以尝试分配一个名为的属性NameReSharper将提供创建该属性的选项:

    ReSharper正确猜测类型,但可以让你改变它:

    另一种构建实体的方法是使用实时模板。由于ReSharper在安装时会自动导入VisualStudio模板,因此您可以使用道具模板快速向您的实体添加属性:

    实体建立

    尽管在很多情况下,您会希望尽可能简化您的实体,但在某些情况下,您需要向实体添加其他功能。例如,初始化构造函数使您的实体更易于使用。幸运的是,对于这样的场合,我们有ReSharperGenerateMenuAlt+Insert)。该菜单可让您将各种功能添加到现有类型中。

    假设您想要将完全初始化构造函数添加到我们的Person类型中。要做到这一点,只需Alt+Insert在课堂上按下,然后选择Constructor

    您将看到一个对话框,询问您想要初始化哪些属性:

    如果你选择所有的属性并按下Finish,你的类将获得下面生成的构造函数:

    Public Person(stringname,intage)

    {

    Name=name;

    Age=age;

    }

    如果你希望你的实体在类似的集合中具有可比性和易于宿主性HashSet<T>,那么你需要实现平等成员-一个正确的艰巨任务!幸运的是,ReSharperGenerate菜单再次有一个对应的选项,它可以让你实现:

  • Equality operators ==!=
  • 正确的Equals()overloads and – optionally – the IEquatable<T> 接口
  • 一个好GetHashCode()方法

    你可以相信ReSharper的特别照顾您的所有特性-它会执行所有正确的null检查,并会做任何财产比较,Equals()==根据类型进行比较。

    最后一个例子(有更多可用选项)是自动创建一个ToString()方法。再次,您可以选择哪些属性参与其中,在您完成之后,ReSharper会生成一个整洁的实现:

    Public override string ToString()

    {

    Return string.Format("Name:{0},Age:{1}",Name,Age);

    }

    请注意,即使您的ORM为您构建了基本实体类,也可以使用这些功能。由于生成的类通常是部分的,因此不会阻止您创建该类的另一部分并在其上运行生成操作。

    基础设施

    在准备好实体之后,现在应该设置用于处理数据库的基础结构。这些的具体内容取决于您使用的ORM或驱动程序,但在此我们将看看NoRMMongoDB的用法。

    假设你从下面的代码开始:

    Void AddPerson()

    {

    using(var m=new Mongo("personnel","localhost","27017",string.Empty))

    {

    Var coll=m.GetCollection<Person>("people");

     

    Var p=new Person("Jack",20);

    coll.Insert(p);

    }

    }

    我们可以做的第一件事是重构数据库连接数据。为此,让我们使用ReSharper重构这个快捷方式(Ctrl+Shift+Rnew并选择语句并选择ExtractMethod选项:

    因此,ReSharper为您提供配置方法的选项。我们称之为GetDatabase()

    以下是ReSharper的产品:

    Private static MongoGetDatabase()

    {

    Return new Mongo("personnel","localhost","27017",string.Empty);

    }

    原来的电话GetDatabase()当然被替换掉了。

    ReSharperVSTO

    无论您使用哪种数据库和驱动程序/ORM,在您的应用程序中设置数据访问的任务都非常相似。从创建实体到设置存储库,ReSharper都可以帮助您更好,更快地完成工作。

    这一切都始于为您的加载项选择一个模板。尽管Office模板按版本分开,但实际上Office20102013项目是相互兼容的,因此2010年的项目在2013年将运行良好。此处的选择仅影响您的调试可能性,即您选择的版本将导致项目只能在该版本的MSOffice上调试。

    通常情况下,默认项目模板添加了大量的使用语句,ReSharper可以帮助您摆脱:

    缺省事件布线StartupShutdown事件也非常冗长-在下面的屏幕截图中,this前缀是多余的,不需要用新的事件来包装事件布线System.EventHandler

    ReSharper不是逐个解决这些问题,而是为您提供多种选择。首先,每种类型的问题都可以在特定的范围内修复-在文件,项目或整个解决方案中:

    或者,如果您想修复不同类型的代码样式问题,则可以调用代码清理操作Ctrl+E,C)。此操作是可配置的,可让您选择要解决的问题类型:

    顺便说一句,如果你认为区域不好,你可能想要删除这些方法的#region指令InternalStartup()ReSharper为您提供了一个上下文操作,可以立即执行此操作

    现在,您可能希望将自己的功能添加到加载项中。如果您愿意,您可以直接在加载项文件中添加您的类,因为完成后,ReSharper会为您提供上下文操作以将该类移动到单独的文件中:

    现在,几乎可以确定您将订阅各种活动,例如通过功能区中按钮生成的事件。您不必拘泥于基于下划线的命名约定-只需按Ctrl+R,R即可重命名该方法。ReSharper询问你如何重新命名处理程序,甚至给出建议:

    当然,如果出于某种原因,最终会重命名代码中的方法-这不是问题,ReSharper会跟踪这些更改。Alt+Enter当重命名的符号被一个边框包围时,只需按下,其中一个动作将提供应用相同的重命名重构

    使用ReSharper导航也很轻松。例如,要在功能区加载时查找代码中的位置,只需按下Ctrl+T即可打开"转至所有内容"对话框。开始输入Ribbon,当然会在列表中看到确切的方法,以及类型:

    ReSharper还有一个方便的NavigateTo菜单,可以通过按下来打开Alt+`。当你想从一个特定的符号导航时这很有用。例如,假设您想查看生成的方法ThisAddIn。你所做的是,首先,通过GotoType找到它(按Ctrl+T两次,然后开始输入它的CamelHumps缩写):

    然后,将光标放在课程名称上,按Alt+`以调出导航至菜单并选择相关文件

    现在,ReSharper向您展示了这个部分类的第二部分。您只需选择要导航的文件即可:

    希望本指南向您展示了ReSharper可以帮助开发VSTO插件的一些方法。

     

     

posted @ 2018-03-06 19:35  CharyGao  阅读(889)  评论(0编辑  收藏  举报