English 中文(简体)
How can I find which property getters have side effects using NDepend?
原标题:

A familiar problem using VisualStudio is the mysterious calling of property getters. If these have side effects (the most common being of the form if (foo == null) foo = new foo(); return foo; ), then the fact that the debugger Locals and Watch windows call the properties - without even hitting any break points - can lead to unexpected effects when debugging.

There is a simple solution to this: just tag the property with the attribute

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]

So how can I find getters which may have side effects in a large code base?

NDepend is the tool of choice for this kind of thing: using its CQL language I can find all the properties which, for example, directly change the state of their containing instance:

         SELECT METHODS FROM ASSEMBLIES "FOO" 
         WHERE IsPropertyGetter AND ChangesObjectState 

This only finds those getters which change a field directly: how can I find ones which change it indirectly, e.g. by calling an Initialize() method?

最佳回答

Joel, this is possible thanks to Code Query through LINQ capabilities (CQLinq). Here is a CQLinq query that detect deep mutability for property getters. For each getters that provokes mutability, the code query shows the set of fields assigned.

// Restrict the iteration only on property getters
// that are changing states or that call a method that changes state
let propertyGetters = Application.Methods.Where(m => m.IsPropertyGetter)

let methodsThatChangeState = 
  Application.Methods.Where(m => m.ChangesObjectState || m.ChangesTypeState)

from m in propertyGetters.DepthOfIsUsingAny(methodsThatChangeState).DefinitionDomain
          .Union(propertyGetters.Intersect(methodsThatChangeState))

// Find all methods called directly or indirectly by the property getter
let methodsCalledIndirectly = 
        m.MethodsCalled.FillIterative(
           methods => methods.SelectMany(m1 => m1.MethodsCalled))
        .DefinitionDomain
        .Union(m.ToEnumerable())

// Gather all field assigned that are not generated by the compiler
let fieldsAssigned = methodsCalledIndirectly
                     .SelectMany(m1 => m1.FieldsAssigned)
                     .Where(f => !f.IsGeneratedByCompiler)

where fieldsAssigned.Any()
orderby fieldsAssigned.Count() descending 
select new { m, fieldsAssigned }

This query is complex, mainly because I optimized it, to first keep only getters that themselves changing state, or that are calling directly or indirectly a method that is changing state (call to DepthOfIsUsingAny()).

Then, for each of this getter, we build the set of all methods called directly or indirectly (thanks to a call to FillIterative()), and we gather all fields assigned by all this method.

Concretely the query result looks like:

enter image description here

问题回答

暂无回答




相关问题
How can I edit a mutable property in Objective C?

I am trying to edit a mutable array from a property and can t seem to directly make it work. Consider the following code that seems to work, but seems also very inefficient; I have to copy the whole ...

Implicit conversion from void to XmlDocument

Probably a stupid question, but I m quite new to the whole "get-and-set-property"-kind of programming; I keep getting a compiling-error on this part of my code; private string _File = "Session.xml"; ...

Property binding across controls in WPF

I have two UserControls that I want to display in a Window. The value of the property "SelectedItem" of the first UserControl should be set to the second UserControl s "SelectedItem" property. How do ...

@staticmethod with @property

I want Stats.singleton.twitter_count += 1 and I thought I could do class Stats: singleton_object = None @property @staticmethod def singleton(): if Stats.singleton_object: ...

热门标签