Visual Studio:查找特定类型的所有引用

时间:2021-09-11 09:10:05

I converted a (C#) struct into a class and need to go through all uses of the type to ensure that there are no undesired effects of the former implicit copy and now reference behaviours.

我将一个(C#)结构转换为一个类,需要经历所有类型的使用,以确保前一个隐式副本和现在的引用行为不会产生不良影响。

Is there a way to find all references, where this specific type is used/involved?

有没有办法找到所有引用,其中使用/涉及此特定类型?

I tried Find all Referenceson the type, and get all locations where the type name is explicitely stated, which is a good start.

我尝试了查找所有Referenceson类型,并获得明确说明类型名称的所有位置,这是一个良好的开端。

However, I don't get the locations where an instance of this type is returned and modified. Specifically the lines where I assign the return value to an implicitely typed variable using var, or all assignments to previously defined variables.

但是,我没有获得返回和修改此类型的实例的位置。特别是我使用var将返回值分配给隐含类型变量的行,或者对先前定义的变量的所有赋值。

Are there any features or tricks I could use? I guess, this particular case of struct-to-class conversion occurs quite often. Maybe you have some advice how to find all possible issues?

我可以使用任何功能或技巧吗?我想,这种结构到类转换的特殊情况经常发生。也许你有一些建议如何找到所有可能的问题?

4 个解决方案

#1


5  

You could rename manually the class... every error is one place where it is used. But I think that the Visual Studio will stop after a certain number of errors.

您可以手动重命名该类...每个错误都是使用它的地方。但我认为Visual Studio将在一定数量的错误后停止。

You could mark as [Obsolete] the class, all its properties, all its methods. Then you would have a warning every time you used them.

您可以将该类及其所有属性及其所有方法标记为[已废弃]。然后每次使用它们时都会发出警告。

Note that the [Obsolete] "trick" has some limitations:

请注意,[Obsolete]“技巧”有一些限制:

[Obsolete]
public class MyClass
{
}

public static void Test1(MyClass test2) // This line has a warning
{
    var y = test2; // ***This line doesn't have a warning***
    MyClass z = test2; // This line has a warning
}

so it is the same as Find all References...

所以它与查找所有参考文献相同...

Another solution, based on FxCop/Code Analysis of Visual Studio:

另一种解决方案,基于Visual Studio的FxCop / Code Analysis:

This is a custom rule, based on the instructions of http://blogs.msdn.com/b/codeanalysis/archive/2010/03/26/how-to-write-custom-static-code-analysis-rules-and-integrate-them-into-visual-studio-2010.aspx

这是一个自定义规则,基于http://blogs.msdn.com/b/codeanalysis/archive/2010/03/26/how-to-write-custom-static-code-analysis-rules-and的说明-integrate了他们,成为视觉工作室,2010.aspx

The Default Namespace of the assembly (you can set in the properties) must be MyCustomFxCopRules. The Platform target x86.

程序集的默认名称空间(您可以在属性中设置)必须是MyCustomFxCopRules。平台目标是x86。

using Microsoft.FxCop.Sdk;

namespace MyCustomFxCopRules
{
    public class StructAssignmentFinder : BaseIntrospectionRule
    {
        public StructAssignmentFinder()
            : base("StructAssignmentFinder", "MyCustomFxCopRules.RuleMetadata", typeof(StructAssignmentFinder).Assembly)
        {
            var ms = new MyStruct();
            var tt = ms;
        }

        public override TargetVisibilities TargetVisibility
        {
            get
            {
                return TargetVisibilities.All;
            }
        }

        public override ProblemCollection Check(ModuleNode module)
        {
            Visit(module);
            return Problems;
        }

public override void VisitAssignmentStatement(AssignmentStatement assignment)
{
    // You could even use FullName
    if ((assignment.Source != null && assignment.Source.Type != null && assignment.Source.Type.Name.Name == "MyStruct") ||
        (assignment.Target != null && assignment.Target.Type != null && assignment.Target.Type.Name.Name == "MyStruct"))
    {
        Problem problem = new Problem(GetNamedResolution("Struct", assignment.Target.Type.Name.Name), assignment);
        Problems.Add(problem);
    }

    base.VisitAssignmentStatement(assignment);
}

public override void VisitConstruct(Construct construct)
{
    Method targetMethod = (Method)((MemberBinding)construct.Constructor).BoundMember;

    if (targetMethod.Parameters.Any(x => x.Type.Name.Name == "MyStruct"))
    {
        Problem problem = new Problem(GetNamedResolution("ParameterType", "MyStruct", targetMethod.Name.Name), construct);
        Problems.Add(problem);
    }

    base.VisitConstruct(construct);
}

public override void VisitMethodCall(MethodCall call)
{
    Method targetMethod = (Method)((MemberBinding)call.Callee).BoundMember;

    if (targetMethod.ReturnType.Name.Name == "MyStruct")
    {
        Problem problem = new Problem(GetNamedResolution("ReturnType", targetMethod.ReturnType.Name.Name, targetMethod.Name.Name), call);
        Problems.Add(problem);
    }

    if (targetMethod.Parameters.Any(x => x.Type.Name.Name == "MyStruct"))
    {
        Problem problem = new Problem(GetNamedResolution("ParameterType", "MyStruct", targetMethod.Name.Name), call);
        Problems.Add(problem);
    }

    base.VisitMethodCall(call);
}

The RuleMetadata.xml (it must be an Embedded Resource)

RuleMetadata.xml(它必须是嵌入式资源)

<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="Rules about Structs">
  <Rule TypeName="StructAssignmentRule" Category="MyRules" CheckId="CR1000">
    <Name>Struct Assignment Finder</Name>
    <Description>Struct Assignment Finder</Description>
    <Url></Url>
    <Resolution Name="Struct">There is an assignment of struct '{0}'.</Resolution>
    <Resolution Name="ReturnType">'{0}' is the return type for a call to '{1}'.</Resolution>
    <Resolution Name="ParameterType">'{0}' is a parameter type for a call to '{1}'.</Resolution>
    <Email></Email>
    <MessageLevel Certainty="100">Warning</MessageLevel>
    <FixCategories>NonBreaking</FixCategories>
    <Owner></Owner>
  </Rule>
</Rules>

Based on this, it is then easy to add other rules for other corner cases that I surely forgot :-)

基于此,很容易为其他角落情况添加其他规则,我肯定忘了:-)

The test file I was using:

我正在使用的测试文件:

public struct MyStruct
{

}

class Test
{
    public Test()
    {
        var ms = new MyStruct();
        var ms2 = ms;

        ms3 = ms;
        ms = ms3;

        ms4 = ms;
        ms = ms4;

        ms4 = ms4;

        new MyObject(default(MyStruct));
    }

    public MyStruct ms3;
    public MyStruct ms4 { get; set; }
}

public class MyObject
{
    public MyObject(MyStruct par1)
    {

    }
}

Note that debugging rules is tricky... It is quite easy to debug with the FxCopCmd.exe, but impossible (I think, not sure) to debug when called directly by Visual Studio.

请注意,调试规则很棘手......使用FxCopCmd.exe进行调试非常容易,但是在Visual Studio直接调用时无法调试(我认为,不确定)。

#2


2  

The answers and comments led me to a satisfactory solution, that possibly helps others, so I thought I'd post it.

答案和评论使我找到了一个令人满意的解决方案,这可能有助于其他人,所以我想我会发布它。

The question was not so much to find all uses, but only the "problematic" ones, namely the write accesses to the public members. Instead of finding all references to the members, as suggested in this answer I only want to find the write access. Therefore, I used a rewriting strategy like indicated in this answer and made all members write only, so the compiler would complain about the dangerous write accesses only.

问题不在于找到所有用途,而只是“有问题”的用途,即对公众成员的写入访问。而不是找到对成员的所有引用,如本回答中所建议的,我只想找到写访问权限。因此,我使用了这个答案中指出的重写策略,并使所有成员都只写,因此编译器只会抱怨危险的写访问。

This in turn transformed the struct/class into an immutable type as outlined in the comments. This made a much cleaner design. I simply rewrote all write accesses where the compiler complained, to respect the immutable design. Thereafter, struct and class are largely exchangable and the switching was easy.

这反过来将struct / class转换为注释中概述的不可变类型。这使得设计更加清洁。我简单地重写了编译器抱怨的所有写访问,以尊重不可变的设计。此后,结构和类很大程度上可以交换,并且切换很容易。

Only trouble were calls to the default constructors of the struct, which was no longer present in the class. But I no longer needed them, since with the class I could simply set these cases to null.

只有问题是对结构的默认构造函数的调用,该结构在类中不再存在。但是我不再需要它们,因为在类中我可以简单地将这些情况设置为null。

#3


1  

You could do a Find All References on each of the class non-private members, one at a time. It would show every read and write to those members.

您可以在每个类非私有成员上执行“查找所有引用”,一次一个。它将显示对这些成员的每次读写。

#4


0  

If you have Visual Studio Web Essentials Extension installed then its very easy. Check screenshot below. On clicking on highlighted link in red you can see all reference of particular type. Visual Studio:查找特定类型的所有引用

如果安装了Visual Studio Web Essentials Extension,则非常容易。查看下面的截图。点击红色突出显示的链接,您可以看到特定类型的所有参考。

#1


5  

You could rename manually the class... every error is one place where it is used. But I think that the Visual Studio will stop after a certain number of errors.

您可以手动重命名该类...每个错误都是使用它的地方。但我认为Visual Studio将在一定数量的错误后停止。

You could mark as [Obsolete] the class, all its properties, all its methods. Then you would have a warning every time you used them.

您可以将该类及其所有属性及其所有方法标记为[已废弃]。然后每次使用它们时都会发出警告。

Note that the [Obsolete] "trick" has some limitations:

请注意,[Obsolete]“技巧”有一些限制:

[Obsolete]
public class MyClass
{
}

public static void Test1(MyClass test2) // This line has a warning
{
    var y = test2; // ***This line doesn't have a warning***
    MyClass z = test2; // This line has a warning
}

so it is the same as Find all References...

所以它与查找所有参考文献相同...

Another solution, based on FxCop/Code Analysis of Visual Studio:

另一种解决方案,基于Visual Studio的FxCop / Code Analysis:

This is a custom rule, based on the instructions of http://blogs.msdn.com/b/codeanalysis/archive/2010/03/26/how-to-write-custom-static-code-analysis-rules-and-integrate-them-into-visual-studio-2010.aspx

这是一个自定义规则,基于http://blogs.msdn.com/b/codeanalysis/archive/2010/03/26/how-to-write-custom-static-code-analysis-rules-and的说明-integrate了他们,成为视觉工作室,2010.aspx

The Default Namespace of the assembly (you can set in the properties) must be MyCustomFxCopRules. The Platform target x86.

程序集的默认名称空间(您可以在属性中设置)必须是MyCustomFxCopRules。平台目标是x86。

using Microsoft.FxCop.Sdk;

namespace MyCustomFxCopRules
{
    public class StructAssignmentFinder : BaseIntrospectionRule
    {
        public StructAssignmentFinder()
            : base("StructAssignmentFinder", "MyCustomFxCopRules.RuleMetadata", typeof(StructAssignmentFinder).Assembly)
        {
            var ms = new MyStruct();
            var tt = ms;
        }

        public override TargetVisibilities TargetVisibility
        {
            get
            {
                return TargetVisibilities.All;
            }
        }

        public override ProblemCollection Check(ModuleNode module)
        {
            Visit(module);
            return Problems;
        }

public override void VisitAssignmentStatement(AssignmentStatement assignment)
{
    // You could even use FullName
    if ((assignment.Source != null && assignment.Source.Type != null && assignment.Source.Type.Name.Name == "MyStruct") ||
        (assignment.Target != null && assignment.Target.Type != null && assignment.Target.Type.Name.Name == "MyStruct"))
    {
        Problem problem = new Problem(GetNamedResolution("Struct", assignment.Target.Type.Name.Name), assignment);
        Problems.Add(problem);
    }

    base.VisitAssignmentStatement(assignment);
}

public override void VisitConstruct(Construct construct)
{
    Method targetMethod = (Method)((MemberBinding)construct.Constructor).BoundMember;

    if (targetMethod.Parameters.Any(x => x.Type.Name.Name == "MyStruct"))
    {
        Problem problem = new Problem(GetNamedResolution("ParameterType", "MyStruct", targetMethod.Name.Name), construct);
        Problems.Add(problem);
    }

    base.VisitConstruct(construct);
}

public override void VisitMethodCall(MethodCall call)
{
    Method targetMethod = (Method)((MemberBinding)call.Callee).BoundMember;

    if (targetMethod.ReturnType.Name.Name == "MyStruct")
    {
        Problem problem = new Problem(GetNamedResolution("ReturnType", targetMethod.ReturnType.Name.Name, targetMethod.Name.Name), call);
        Problems.Add(problem);
    }

    if (targetMethod.Parameters.Any(x => x.Type.Name.Name == "MyStruct"))
    {
        Problem problem = new Problem(GetNamedResolution("ParameterType", "MyStruct", targetMethod.Name.Name), call);
        Problems.Add(problem);
    }

    base.VisitMethodCall(call);
}

The RuleMetadata.xml (it must be an Embedded Resource)

RuleMetadata.xml(它必须是嵌入式资源)

<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="Rules about Structs">
  <Rule TypeName="StructAssignmentRule" Category="MyRules" CheckId="CR1000">
    <Name>Struct Assignment Finder</Name>
    <Description>Struct Assignment Finder</Description>
    <Url></Url>
    <Resolution Name="Struct">There is an assignment of struct '{0}'.</Resolution>
    <Resolution Name="ReturnType">'{0}' is the return type for a call to '{1}'.</Resolution>
    <Resolution Name="ParameterType">'{0}' is a parameter type for a call to '{1}'.</Resolution>
    <Email></Email>
    <MessageLevel Certainty="100">Warning</MessageLevel>
    <FixCategories>NonBreaking</FixCategories>
    <Owner></Owner>
  </Rule>
</Rules>

Based on this, it is then easy to add other rules for other corner cases that I surely forgot :-)

基于此,很容易为其他角落情况添加其他规则,我肯定忘了:-)

The test file I was using:

我正在使用的测试文件:

public struct MyStruct
{

}

class Test
{
    public Test()
    {
        var ms = new MyStruct();
        var ms2 = ms;

        ms3 = ms;
        ms = ms3;

        ms4 = ms;
        ms = ms4;

        ms4 = ms4;

        new MyObject(default(MyStruct));
    }

    public MyStruct ms3;
    public MyStruct ms4 { get; set; }
}

public class MyObject
{
    public MyObject(MyStruct par1)
    {

    }
}

Note that debugging rules is tricky... It is quite easy to debug with the FxCopCmd.exe, but impossible (I think, not sure) to debug when called directly by Visual Studio.

请注意,调试规则很棘手......使用FxCopCmd.exe进行调试非常容易,但是在Visual Studio直接调用时无法调试(我认为,不确定)。

#2


2  

The answers and comments led me to a satisfactory solution, that possibly helps others, so I thought I'd post it.

答案和评论使我找到了一个令人满意的解决方案,这可能有助于其他人,所以我想我会发布它。

The question was not so much to find all uses, but only the "problematic" ones, namely the write accesses to the public members. Instead of finding all references to the members, as suggested in this answer I only want to find the write access. Therefore, I used a rewriting strategy like indicated in this answer and made all members write only, so the compiler would complain about the dangerous write accesses only.

问题不在于找到所有用途,而只是“有问题”的用途,即对公众成员的写入访问。而不是找到对成员的所有引用,如本回答中所建议的,我只想找到写访问权限。因此,我使用了这个答案中指出的重写策略,并使所有成员都只写,因此编译器只会抱怨危险的写访问。

This in turn transformed the struct/class into an immutable type as outlined in the comments. This made a much cleaner design. I simply rewrote all write accesses where the compiler complained, to respect the immutable design. Thereafter, struct and class are largely exchangable and the switching was easy.

这反过来将struct / class转换为注释中概述的不可变类型。这使得设计更加清洁。我简单地重写了编译器抱怨的所有写访问,以尊重不可变的设计。此后,结构和类很大程度上可以交换,并且切换很容易。

Only trouble were calls to the default constructors of the struct, which was no longer present in the class. But I no longer needed them, since with the class I could simply set these cases to null.

只有问题是对结构的默认构造函数的调用,该结构在类中不再存在。但是我不再需要它们,因为在类中我可以简单地将这些情况设置为null。

#3


1  

You could do a Find All References on each of the class non-private members, one at a time. It would show every read and write to those members.

您可以在每个类非私有成员上执行“查找所有引用”,一次一个。它将显示对这些成员的每次读写。

#4


0  

If you have Visual Studio Web Essentials Extension installed then its very easy. Check screenshot below. On clicking on highlighted link in red you can see all reference of particular type. Visual Studio:查找特定类型的所有引用

如果安装了Visual Studio Web Essentials Extension,则非常容易。查看下面的截图。点击红色突出显示的链接,您可以看到特定类型的所有参考。