Olá pessoal. Tudo certo?!
Se estivermos atentos ao feedback que nosso código nos dá, temos a possibilidade de melhorar nosso design.
Dois “gritos” evidentes são:
No post de hoje, mostro um refactoring no FluentCodeMetrics. O código está no GitHub.
Para começar, vamos dar uma olhada no método que desejamos melhorar. Veja:
public static IEnumerable<Type>
GetReferencedTypesByNewobjInstruction(this Type that)
{
var assembly = AssemblyCache.Load(that.Assembly.GetName().Name);
var typeDef = assembly.MainModule.Types
.First(type => type.FullName == that.FullName);
return
from method in typeDef.Methods
from instruction in method.Body.Instructions
where instruction.OpCode == OpCodes.Newobj
let operand = instruction.Operand as MethodReference
let typeFullName = operand.DeclaringType.FullName
let type = Type.GetType(typeFullName)
where type != null
select type;
}
public static IEnumerable<Type>
GetReferencedTypes(this Type that)
{
const BindingFlags flags = BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
var typeMetaAttributeTypes =
from attribute in that.GetCustomAttributes(true)
select attribute.GetType();
var fieldMetaAttributeTypes =
from field in that.GetFields(flags)
from attribute in field.GetCustomAttributes(true)
select attribute.GetType();
var methodMetaAttributeTypes =
from method in that.GetMethods(flags)
from attribute in method.GetCustomAttributes(true)
select attribute.GetType();
var methodParameterMetaAttributeTypes =
from method in that.GetMethods(flags)
from parameter in method.GetParameters()
from attribute in parameter.GetCustomAttributes(true)
select attribute.GetType();
var fieldTypes =
from field in that.GetFields(flags)
select field.FieldType;
var propertyTypes =
from property in that.GetProperties(flags)
select property.PropertyType;
var methodReturnTypes =
from method in that.GetMethods(flags)
where method.ReturnType != typeof(void)
select method.ReturnType;
var methodParameterTypes =
from method in that.GetMethods(flags)
from parameter in method.GetParameters()
select parameter.ParameterType;
var ctorParameterTypes =
from ctor in that.GetConstructors(flags)
from parameter in ctor.GetParameters()
select parameter.ParameterType;
return new[] { that.BaseType }
.Union(that.GetReferencedTypesByNewobjInstruction())
.Union(typeMetaAttributeTypes)
.Union(fieldMetaAttributeTypes)
.Union(methodMetaAttributeTypes)
.Union(methodParameterMetaAttributeTypes)
.Union(ctorParameterTypes)
.Union(methodParameterTypes)
.Union(fieldTypes)
.Union(propertyTypes)
.Union(methodReturnTypes)
.Distinct();
}
Como você pode ver, este método está “grande demais”. Tão grande que acabei “quebrando” a lógica em duas partes.
A primeira alteração, evidente, é extrair métodos. Veja o resultado:
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil.Cil;
using TypeFilter = FluentCodeMetrics.Core.TypeFilters.TypeFilter;
namespace FluentCodeMetrics.Core
{
public static class CeExtensions
{
public static int ComputeCe(this Type that)
{
return that
.GetReferencedTypes()
.Count();
}
const BindingFlags Flags = BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
public static IEnumerable<Type>
GetReferencedTypes(this Type that)
{
var typeMetaAttributeTypes = GetTypeMetaAttributeTypes(that);
var fieldMetaAttributeTypes = GetFieldMetaAttributeTypes(that);
var methodMetaAttributeTypes = GetMethodMetaAttributeTypes(that);
var methodParameterMetaAttributeTypes = GetMethodParameterMetaAttributeTypes(that);
var fieldTypes = GetFieldTypes(that);
var propertyTypes = GetPropertyTypes(that);
var methodReturnTypes = GetMethodReturnTypes(that);
var methodParameterTypes = GetMethodParameterTypes(that);
var ctorParameterTypes = GetCtorParameterTypes(that);
return new[] { that.BaseType }
.Union(that.GetReferencedTypesByNewobjInstruction())
.Union(typeMetaAttributeTypes)
.Union(fieldMetaAttributeTypes)
.Union(methodMetaAttributeTypes)
.Union(methodParameterMetaAttributeTypes)
.Union(ctorParameterTypes)
.Union(methodParameterTypes)
.Union(fieldTypes)
.Union(propertyTypes)
.Union(methodReturnTypes)
.Distinct();
}
public static IEnumerable<Type>
GetReferencedTypesByNewobjInstruction(this Type that)
{
var assembly = AssemblyCache.Load(that.Assembly.GetName().Name);
var typeDef = assembly.MainModule.Types
.First(type => type.FullName == that.FullName);
return
from method in typeDef.Methods
from instruction in method.Body.Instructions
where instruction.OpCode == OpCodes.Newobj
let operand = instruction.Operand as MethodReference
let typeFullName = operand.DeclaringType.FullName
let type = Type.GetType(typeFullName)
where type != null
select type;
}
private static IEnumerable<Type> GetCtorParameterTypes(Type that)
{
var ctorParameterTypes =
from ctor in that.GetConstructors(Flags)
from parameter in ctor.GetParameters()
select parameter.ParameterType;
return ctorParameterTypes;
}
private static IEnumerable<Type> GetMethodParameterTypes(Type that)
{
var methodParameterTypes =
from method in that.GetMethods(Flags)
from parameter in method.GetParameters()
select parameter.ParameterType;
return methodParameterTypes;
}
private static IEnumerable<Type> GetMethodReturnTypes(Type that)
{
var methodReturnTypes =
from method in that.GetMethods(Flags)
where method.ReturnType != typeof (void)
select method.ReturnType;
return methodReturnTypes;
}
private static IEnumerable<Type> GetPropertyTypes(Type that)
{
var propertyTypes =
from property in that.GetProperties(Flags)
select property.PropertyType;
return propertyTypes;
}
private static IEnumerable<Type> GetFieldTypes(Type that)
{
var fieldTypes =
from field in that.GetFields(Flags)
select field.FieldType;
return fieldTypes;
}
private static IEnumerable<Type> GetMethodParameterMetaAttributeTypes(Type that)
{
var methodParameterMetaAttributeTypes =
from method in that.GetMethods(Flags)
from parameter in method.GetParameters()
from attribute in parameter.GetCustomAttributes(true)
select attribute.GetType();
return methodParameterMetaAttributeTypes;
}
private static IEnumerable<Type> GetMethodMetaAttributeTypes(Type that)
{
var methodMetaAttributeTypes =
from method in that.GetMethods(Flags)
from attribute in method.GetCustomAttributes(true)
select attribute.GetType();
return methodMetaAttributeTypes;
}
private static IEnumerable<Type> GetFieldMetaAttributeTypes(Type that)
{
var fieldMetaAttributeTypes =
from field in that.GetFields(Flags)
from attribute in field.GetCustomAttributes(true)
select attribute.GetType();
return fieldMetaAttributeTypes;
}
private static IEnumerable<Type> GetTypeMetaAttributeTypes(Type that)
{
return
from attribute in that.GetCustomAttributes(true)
select attribute.GetType();
}
public static int ComputeCe(this Type that, TypeFilter filter)
{
return that
.GetReferencedTypes()
.Count(filter.Check);
}
}
}
A classe CeExtensions está “estressada”. A maior parte dos métodos está “pesquisando” tipos. Extrair esses métodos para outra classe parece a saída evidente. Veja o resultado:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace FluentCodeMetrics.Core
{
public static class ReferencesInspector
{
private const BindingFlags Flags = BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
public static IEnumerable<Type>
GetReferencedTypesByNewobjInstruction(this Type that)
{
var assembly = AssemblyCache.Load(that.Assembly.GetName().Name);
var typeDef = assembly.MainModule.Types
.First(type => type.FullName == that.FullName);
return
from method in typeDef.Methods
from instruction in method.Body.Instructions
where instruction.OpCode == OpCodes.Newobj
let operand = instruction.Operand as MethodReference
let typeFullName = operand.DeclaringType.FullName
let type = Type.GetType(typeFullName)
where type != null
select type;
}
public static IEnumerable<Type> GetCtorParameterTypes(Type that)
{
return
from ctor in that.GetConstructors(Flags)
from parameter in ctor.GetParameters()
select parameter.ParameterType;
}
public static IEnumerable<Type> GetMethodParameterTypes(Type that)
{
return
from method in that.GetMethods(Flags)
from parameter in method.GetParameters()
select parameter.ParameterType;
}
public static IEnumerable<Type> GetMethodReturnTypes(Type that)
{
return
from method in that.GetMethods(Flags)
where method.ReturnType != typeof(void)
select method.ReturnType;
}
public static IEnumerable<Type> GetPropertyTypes(Type that)
{
return
from property in that.GetProperties(Flags)
select property.PropertyType;
}
public static IEnumerable<Type> GetFieldTypes(Type that)
{
return
from field in that.GetFields(Flags)
select field.FieldType;
}
public static IEnumerable<Type> GetMethodParameterMetaAttributeTypes(Type that)
{
return
from method in that.GetMethods(Flags)
from parameter in method.GetParameters()
from attribute in parameter.GetCustomAttributes(true)
select attribute.GetType();
}
public static IEnumerable<Type> GetMethodMetaAttributeTypes(Type that)
{
return
from method in that.GetMethods(Flags)
from attribute in method.GetCustomAttributes(true)
select attribute.GetType();
}
public static IEnumerable<Type> GetFieldMetaAttributeTypes(Type that)
{
return
from field in that.GetFields(Flags)
from attribute in field.GetCustomAttributes(true)
select attribute.GetType();
}
public static IEnumerable<Type> GetTypeMetaAttributeTypes(Type that)
{
return
from attribute in that.GetCustomAttributes(true)
select attribute.GetType();
}
}
}
ComputeCe ficou bem menor. Veja:
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil.Cil;
using TypeFilter = FluentCodeMetrics.Core.TypeFilters.TypeFilter;
namespace FluentCodeMetrics.Core
{
public static class CeExtensions
{
public static int ComputeCe(this Type that)
{
return that
.GetReferencedTypes()
.Count();
}
public static IEnumerable<Type>
GetReferencedTypes(this Type that)
{
var typeMetaAttributeTypes = ReferencesInspector.GetTypeMetaAttributeTypes(that);
var fieldMetaAttributeTypes = ReferencesInspector.GetFieldMetaAttributeTypes(that);
var methodMetaAttributeTypes = ReferencesInspector.GetMethodMetaAttributeTypes(that);
var methodParameterMetaAttributeTypes = ReferencesInspector.GetMethodParameterMetaAttributeTypes(that);
var fieldTypes = ReferencesInspector.GetFieldTypes(that);
var propertyTypes = ReferencesInspector.GetPropertyTypes(that);
var methodReturnTypes = ReferencesInspector.GetMethodReturnTypes(that);
var methodParameterTypes = ReferencesInspector.GetMethodParameterTypes(that);
var ctorParameterTypes = ReferencesInspector.GetCtorParameterTypes(that);
return new[] { that.BaseType }
.Union(that.GetReferencedTypesByNewobjInstruction())
.Union(typeMetaAttributeTypes)
.Union(fieldMetaAttributeTypes)
.Union(methodMetaAttributeTypes)
.Union(methodParameterMetaAttributeTypes)
.Union(ctorParameterTypes)
.Union(methodParameterTypes)
.Union(fieldTypes)
.Union(propertyTypes)
.Union(methodReturnTypes)
.Distinct();
}
public static int ComputeCe(this Type that, TypeFilter filter)
{
return that
.GetReferencedTypes()
.Count(filter.Check);
}
}
}
Não há razões justificáveis para manter nossos métodos de “consulta ao código” estáticos. Veja:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace FluentCodeMetrics.Core
{
public class ReferencesInspector
{
// ReSharper disable InconsistentNaming
private readonly Type workingType;
// ReSharper restore InconsistentNaming
public ReferencesInspector(Type type)
{
workingType = type;
}
public static ReferencesInspector For<T>()
{
return For(typeof(T));
}
public static ReferencesInspector For(Type type)
{
return new ReferencesInspector(type);
}
private const BindingFlags Flags = BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
public IEnumerable<Type>
ByNewobjInstruction()
{
var assembly = AssemblyCache.Load(workingType.Assembly.GetName().Name);
var typeDef = assembly.MainModule.Types
.First(type => type.FullName == workingType.FullName);
return
from method in typeDef.Methods
from instruction in method.Body.Instructions
where instruction.OpCode == OpCodes.Newobj
let operand = instruction.Operand as MethodReference
let typeFullName = operand.DeclaringType.FullName
let type = Type.GetType(typeFullName)
where type != null
select type;
}
public IEnumerable<Type>
ByCtorParametersTypes()
{
return
from ctor in workingType.GetConstructors(Flags)
from parameter in ctor.GetParameters()
select parameter.ParameterType;
}
public IEnumerable<Type>
ByMethodsParametersTypes()
{
return
from method in workingType.GetMethods(Flags)
from parameter in method.GetParameters()
select parameter.ParameterType;
}
public IEnumerable<Type>
ByMethodsReturnTypes()
{
return
from method in workingType.GetMethods(Flags)
where method.ReturnType != typeof(void)
select method.ReturnType;
}
public IEnumerable<Type>
ByPropertiesTypes()
{
return
from property in workingType.GetProperties(Flags)
select property.PropertyType;
}
public IEnumerable<Type>
ByFieldsTypes()
{
return
from field in workingType.GetFields(Flags)
select field.FieldType;
}
public IEnumerable<Type>
ByParametersMetaAttributesTypes()
{
return
from method in workingType.GetMethods(Flags)
from parameter in method.GetParameters()
from attribute in parameter.GetCustomAttributes(true)
select attribute.GetType();
}
public IEnumerable<Type>
OfMethodsMetaAttributesTypes()
{
return
from method in workingType.GetMethods(Flags)
from attribute in method.GetCustomAttributes(true)
select attribute.GetType();
}
public IEnumerable<Type>
OfFieldsMetaAttributesTypes()
{
return
from field in workingType.GetFields(Flags)
from attribute in field.GetCustomAttributes(true)
select attribute.GetType();
}
public IEnumerable<Type> OfMetaAttributesTypes()
{
return
from attribute in workingType.GetCustomAttributes(true)
select attribute.GetType();
}
}
}
Ainda indeciso quanto ao nome dos métodos. Mas, no caminho. Vejamos como ficou CeExtensions:
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil.Cil;
using TypeFilter = FluentCodeMetrics.Core.TypeFilters.TypeFilter;
namespace FluentCodeMetrics.Core
{
public static class CeExtensions
{
public static int ComputeCe(this Type that)
{
return that
.GetReferencedTypes()
.Count();
}
public static IEnumerable<Type>
GetReferencedTypes(this Type that)
{
var inspector = ReferencesInspector.For(that);
var referencedTypesByNewobjInstruction = inspector.OfNewobjInstruction();
var typeMetaAttributeTypes = inspector.OfMetaAttributesTypes();
var fieldMetaAttributeTypes = inspector.OfFieldsMetaAttributesTypes();
var methodMetaAttributeTypes = inspector.OfMethodsMetaAttributesTypes();
var methodParameterMetaAttributeTypes = inspector.OfParametersMetaAttributesTypes();
var fieldTypes = inspector.OfFieldsTypes();
var propertyTypes = inspector.OfPropertiesTypes();
var methodReturnTypes = inspector.OfMethodsReturnTypes();
var methodParameterTypes = inspector.OfMethodsParametersTypes();
var ctorParameterTypes = inspector.OfCtorParametersTypes();
return new[] { that.BaseType }
.Union(referencedTypesByNewobjInstruction)
.Union(typeMetaAttributeTypes)
.Union(fieldMetaAttributeTypes)
.Union(methodMetaAttributeTypes)
.Union(methodParameterMetaAttributeTypes)
.Union(ctorParameterTypes)
.Union(methodParameterTypes)
.Union(fieldTypes)
.Union(propertyTypes)
.Union(methodReturnTypes)
.Distinct();
}
public static int ComputeCe(this Type that, TypeFilter filter)
{
return that
.GetReferencedTypes()
.Count(filter.Check);
}
}
}
Gosto da idéia de ter uma interface fluente para essa “consulta”.
Para começar, resolvi melhorar o retorno dos métodos de consulta. Veja:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace FluentCodeMetrics.Core
{
public class ReferencedTypes :
IEnumerable<Type>
{
private readonly IEnumerable<Type> sourceField;
private readonly Type originalField;
internal ReferencedTypes(IEnumerable<Type> source, Type original)
{
sourceField = source;
originalField = original;
}
public IEnumerator<Type> GetEnumerator()
{
return sourceField.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return sourceField.GetEnumerator();
}
public ReferencesInspector And
{
get { return new ReferencesInspector(originalField, sourceField); }
}
}
}
Agora, aprimorar ReferencesInspector. Veja como finalmente melhoro o nome dos métodos.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace FluentCodeMetrics.Core
{
public class ReferencesInspector
{
// ReSharper disable InconsistentNaming
private readonly Type workingType;
private readonly IEnumerable<Type> other;
// ReSharper restore InconsistentNaming
internal ReferencesInspector(Type type, IEnumerable<Type> other)
{
workingType = type;
this.other = other;
}
private ReferencesInspector(Type type)
{
workingType = type;
other = new Type[] {};
}
public static ReferencesInspector For<T>()
{
return For(typeof(T));
}
public static ReferencesInspector For(Type type)
{
return new ReferencesInspector(type);
}
private const BindingFlags Flags = BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
public ReferencedTypes
FromBaseType()
{
return new ReferencedTypes(
new[] { workingType.BaseType },
workingType
);
}
public ReferencedTypes
FromNewobjInstructions()
{
var assembly = AssemblyCache.Load(workingType.Assembly.GetName().Name);
var typeDef = assembly.MainModule.Types
.First(type => type.FullName == workingType.FullName);
var source =
from method in typeDef.Methods
from instruction in method.Body.Instructions
where instruction.OpCode == OpCodes.Newobj
let operand = instruction.Operand as MethodReference
let typeFullName = operand.DeclaringType.FullName
let type = Type.GetType(typeFullName)
where type != null
select type;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromCtorParameters()
{
var source =
from ctor in workingType.GetConstructors(Flags)
from parameter in ctor.GetParameters()
select parameter.ParameterType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromMethodsParameters()
{
var source =
from method in workingType.GetMethods(Flags)
from parameter in method.GetParameters()
select parameter.ParameterType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromMethodsReturnTypes()
{
var source =
from method in workingType.GetMethods(Flags)
where method.ReturnType != typeof(void)
select method.ReturnType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromProperties()
{
var source =
from property in workingType.GetProperties(Flags)
select property.PropertyType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromFields()
{
var source =
from field in workingType.GetFields(Flags)
select field.FieldType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromParametersMetaAttributes()
{
var source =
from method in workingType.GetMethods(Flags)
from parameter in method.GetParameters()
from attribute in parameter.GetCustomAttributes(true)
select attribute.GetType();
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromMethodsMetaAttributes()
{
var source =
from method in workingType.GetMethods(Flags)
from attribute in method.GetCustomAttributes(true)
select attribute.GetType();
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromFieldsMetaAttributes()
{
var source =
from field in workingType.GetFields(Flags)
from attribute in field.GetCustomAttributes(true)
select attribute.GetType();
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromMetaAttributes()
{
var source =
from attribute in workingType.GetCustomAttributes(true)
select attribute.GetType();
return new ReferencedTypes(other.Union(source), workingType);
}
}
}
Por fim, melhoro o consumo de tais métodos. Veja:
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil.Cil;
using TypeFilter = FluentCodeMetrics.Core.TypeFilters.TypeFilter;
namespace FluentCodeMetrics.Core
{
public static class CeExtensions
{
public static int ComputeCe(this Type that)
{
return that
.GetReferencedTypes()
.Count();
}
public static ReferencedTypes
GetReferencedTypes(this Type that)
{
return ReferencesInspector.For(that)
.FromBaseType()
.And.FromNewobjInstructions()
.And.FromMetaAttributes()
.And.FromFieldsMetaAttributes()
.And.FromMethodsMetaAttributes()
.And.FromParametersMetaAttributes()
.And.FromFields()
.And.FromProperties()
.And.FromMethodsReturnTypes()
.And.FromMethodsParameters()
.And.FromCtorParameters();
}
public static int ComputeCe(this Type that, TypeFilter filter)
{
return that
.GetReferencedTypes()
.Count(filter.Check);
}
}
}
Por que, afinal de contas, GerReferencedTypes está em ComputeCe?! Mudemos ela de nome e de lugar.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace FluentCodeMetrics.Core
{
public class ReferencesInspector
{
// ReSharper disable InconsistentNaming
private readonly Type workingType;
private readonly IEnumerable<Type> other;
// ReSharper restore InconsistentNaming
internal ReferencesInspector(Type type, IEnumerable<Type> other)
{
workingType = type;
this.other = other;
}
private ReferencesInspector(Type type)
{
workingType = type;
other = new Type[] {};
}
public static ReferencesInspector For<T>()
{
return For(typeof(T));
}
public static ReferencesInspector For(Type type)
{
return new ReferencesInspector(type);
}
private const BindingFlags Flags = BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.Public;
public ReferencedTypes
FromBaseType()
{
return new ReferencedTypes(
new[] { workingType.BaseType },
workingType
);
}
public ReferencedTypes
FromNewobjInstructions()
{
var assembly = AssemblyCache.Load(workingType.Assembly.GetName().Name);
var typeDef = assembly.MainModule.Types
.First(type => type.FullName == workingType.FullName);
var source =
from method in typeDef.Methods
from instruction in method.Body.Instructions
where instruction.OpCode == OpCodes.Newobj
let operand = instruction.Operand as MethodReference
let typeFullName = operand.DeclaringType.FullName
let type = Type.GetType(typeFullName)
where type != null
select type;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromCtorParameters()
{
var source =
from ctor in workingType.GetConstructors(Flags)
from parameter in ctor.GetParameters()
select parameter.ParameterType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromMethodsParameters()
{
var source =
from method in workingType.GetMethods(Flags)
from parameter in method.GetParameters()
select parameter.ParameterType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromMethodsReturnTypes()
{
var source =
from method in workingType.GetMethods(Flags)
where method.ReturnType != typeof(void)
select method.ReturnType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromProperties()
{
var source =
from property in workingType.GetProperties(Flags)
select property.PropertyType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromFields()
{
var source =
from field in workingType.GetFields(Flags)
select field.FieldType;
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromParametersMetaAttributes()
{
var source =
from method in workingType.GetMethods(Flags)
from parameter in method.GetParameters()
from attribute in parameter.GetCustomAttributes(true)
select attribute.GetType();
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromMethodsMetaAttributes()
{
var source =
from method in workingType.GetMethods(Flags)
from attribute in method.GetCustomAttributes(true)
select attribute.GetType();
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromFieldsMetaAttributes()
{
var source =
from field in workingType.GetFields(Flags)
from attribute in field.GetCustomAttributes(true)
select attribute.GetType();
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
FromMetaAttributes()
{
var source =
from attribute in workingType.GetCustomAttributes(true)
select attribute.GetType();
return new ReferencedTypes(other.Union(source), workingType);
}
public ReferencedTypes
All()
{
return new ReferencedTypes(FromBaseType()
.And.FromNewobjInstructions()
.And.FromMetaAttributes()
.And.FromFieldsMetaAttributes()
.And.FromMethodsMetaAttributes()
.And.FromParametersMetaAttributes()
.And.FromFields()
.And.FromProperties()
.And.FromMethodsReturnTypes()
.And.FromMethodsParameters()
.And.FromCtorParameters()
.Distinct(), workingType);
}
}
}
Ela virou All, dentro de ReferencesInspector.
Também melhoremos nossa interface fluente para facilitar filtros. Veja:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentCodeMetrics.Core.TypeFilters;
namespace FluentCodeMetrics.Core
{
public class ReferencedTypes :
IEnumerable<Type>
{
private readonly IEnumerable<Type> sourceField;
private readonly Type originalField;
internal ReferencedTypes(IEnumerable<Type> source, Type original)
{
sourceField = source;
originalField = original;
}
public IEnumerator<Type> GetEnumerator()
{
return sourceField.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return sourceField.GetEnumerator();
}
public ReferencesInspector And
{
get
{
return new ReferencesInspector(
originalField,
sourceField
);
}
}
public ReferencedTypes FilterBy(TypeFilter filter)
{
return new ReferencedTypes(
sourceField.Where(filter.Check),
originalField
);
}
}
}
Finalmente, como ficou ComputeCe.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Mono.Cecil;
using FluentCodeMetrics.Core.Cecil;
using Mono.Cecil.Cil;
using TypeFilter = FluentCodeMetrics.Core.TypeFilters.TypeFilter;
namespace FluentCodeMetrics.Core
{
public static class CeExtensions
{
public static int ComputeCe(this Type that)
{
return ReferencesInspector.For(that)
.All()
.Count();
}
public static int ComputeCe(this Type that, TypeFilter filter)
{
return ReferencesInspector.For(that)
.All()
.FilterBy(filter)
.Count();
}
}
}
Como mudamos o design, nossos testes de unidade precisaram ser revistos. Veja:
using System;
using System.Linq;
using System.Collections.Generic;
using FluentCodeMetrics.Core.TypeFilters;
using NUnit.Framework;
using SharpTestsEx;
using FluentCodeMetrics.Core;
using Samples;
namespace FluentCodeMetrics.Tests
{
[TestFixture]
// ReSharper disable InconsistentNaming
public class ReferencesInspectorTests
{
private readonly List<Type> common = new List<Type>()
{
typeof (System.Runtime.TargetedPatchingOptOutAttribute),
typeof (System.Security.SecuritySafeCriticalAttribute),
typeof (System.Runtime.ConstrainedExecution.ReliabilityContractAttribute),
typeof (object),
typeof (string),
typeof (bool),
typeof (int),
typeof (Type)
};
[Test]
public void All_EmptyClass()
{
ReferencesInspector.For(typeof(EmptyClass)).All()
.Should().Have.SameValuesAs(
common
);
}
[Test]
public void All_SingleField()
{
ReferencesInspector.For(typeof(SingleField)).All()
.Should().Have.SameValuesAs(
common.Union(new[]
{
typeof(DateTime)
})
);
}
[Test]
public void All_SingleProperty()
{
ReferencesInspector.For(typeof(SingleProperty)).All()
.Should().Have.SameValuesAs(
common.Union(new[]
{
typeof(DateTime),
typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)
})
);
}
[Test]
public void All_SingleNonAutoProperty()
{
ReferencesInspector.For(typeof(SingleNonAutoProperty)).All()
.Should().Have.SameValuesAs(
common.Union(new[]
{
typeof(DateTime)
})
);
}
[Test]
public void All_FeeMethod()
{
ReferencesInspector.For(typeof(FeeMethod)).All()
.Should().Have.SameValuesAs(
common.Union(new[]
{
typeof(Fee)
})
);
}
[Test]
public void All_SingleArgVoidMethod()
{
ReferencesInspector.For(typeof(SingleArgVoidMethod)).All()
.Should().Have.SameValuesAs(
common.Union(new[]
{
typeof(Fee)
})
);
}
[Test]
public void All_SingleArgCtor()
{
ReferencesInspector.For(typeof(SingleArgCtor)).All()
.Should().Have.SameValuesAs(
common.Union(new[]
{
typeof(Fee)
})
);
}
[Test]
public void All_ExceptionRaiser()
{
ReferencesInspector.For(typeof(ExceptionRaiser)).All()
.Should().Have.SameValuesAs(
common.Union(new[]
{
typeof(Exception)
})
);
}
[Test]
public void All_Attributes()
{
ReferencesInspector.For(typeof(Attributes)).All()
.Should().Have.SameValuesAs(
common.Union(new []
{
typeof(SerializableAttribute), // Class Attribute
typeof(NonSerializedAttribute), // Field Attribute
typeof(FooAttribute), // MethodAttribute
typeof(FooAttribute2) // Parameter Attribute
})
);
}
[Test]
public void All_StaticProperty()
{
ReferencesInspector.For(typeof(StaticMember)).All()
.Should().Have.SameValuesAs(
common.Union(new[]
{
typeof(DateTime),
typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute)
})
);
}
}
// ReSharper restore InconsistentNaming
}
Todo o refactoring melhorou a testabilidade e, em consequência, o design. O código ficou mais reutilizável e inteligente.
Por agora, era isso.
Show de bola o post! Muitas vezes encontramos códigos que precisam de refactoring e os devs não entendem porque é necessário.
Reblogged this on Tiago Padilha's Blog.
Pingback: FluentCodeMetrics – Parte 5 – Reconhecendo dependências em métodos/propriedades estáticas e ignorando Nested Types « Elemar DEV
Pingback: Mais um pequeno refactoring « Elemar DEV