I recently had an ugly bug whereby my collection unexpectedly had a reverse order.
public class WidgetContainer : IWidgetContainer
{
// ...
public void Add(IWidget widget, int? index = null)
{
if (!index.HasValue)
_collection.Add(widget);
else
_collection.Insert(index.Value, widget);
}
}
The calling code was not specifying the index. So, for all intents and purposes, this code should have been working, inserting elements sequentially.
But it didn't.
Then I looked at the interface:
public interface IWidgetContainer
{
void Add(IWidget widget, int? index = 0);
}
Boom.
The calling code resolved the instance by interface, so 0 was used instead of null.
No compiler errors, no warnings - nothing. Can I enable them somewhere?
If not, can I automatically detect and prevent such issues, possibly with a solution test? Mono.Cecil, Reflection are all acceptable.
Applying to an assembly:
Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsClass)
.Select(GetDefaultParameterValuesMismatch)
.Where(m => m.Count() > 0);
IEnumerable<(string Interface, string Class, string Method, string Parameter, object InterfaceParameterValue, object ClassParameterValue)>
GetDefaultParameterValuesMismatch(Type type)
{
var interfaceParameterValues = type
.GetTypeInfo()
.ImplementedInterfaces
.SelectMany(i => i.GetMethods().Select(m => new { Type = i.Name, m }))
.SelectMany(t => t.m.GetParameters().Select(p => new
{
Type = t.Type,
Method = t.m.Name,
Parameter = p.Name,
p.DefaultValue
}));
var classParameterValues = type
.GetTypeInfo()
.GetMethods()
.SelectMany(m => m.GetParameters().Select(p => new
{
Type = type.Name,
Method = m.Name,
Parameter = p.Name,
p.DefaultValue
}));
return interfaceParameterValues
.Zip(classParameterValues, (t1, t2) => new { t1, t2 })
.Where(typePair => !object.Equals(typePair.t1.DefaultValue, (typePair.t2.DefaultValue)))
.Select(typePair => (Interface: typePair.t1.Type,
Class: typePair.t2.Type,
Method: typePair.t1.Method,
Parameter: typePair.t1.Parameter,
InterfaceParameterValue: typePair.t1.DefaultValue,
ClassParameterValue: typePair.t2.DefaultValue));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With