Introduction
Interface implementation on Visual Studio adds initial "throw new NotIImplementedException();
" on each interface member. This is true in other refactoring scenarios.
Usually, a programmer must change each "throw new NotImplementedException()
" manually.
In this tip, I show how to detect a "throw ...
" before calling the member.
Background
Using Reflection's MemberInfo
, we can obtain a MethodBody
class.
MethodBody
class can give us early IL codes without executing them and without special privileges.
Any "throw new NotImplemented();
" is translated as a 6Bytes IL code starting in 115 (IL for new) and ending with 122 (IL for throw). Additional checking ensures no mistakes.
Using the Code
This is an example where we can override not implemented methods on runtime with new functions:
var FuncCreator = MyClass.IsNotImplemented
(nameof(MyClass.FuncCreator)) ? null : MyClass.FuncCreator;
var BeginUpdate = MyClass.IsNotImplemented
(nameof(MyClass.BeginUpdate)) ? null : MyClass.BeginUpdate;
var EndUpdate = fake.IsNotImplemented
(nameof(MyClass.EndUpdate)) ? null : MyClass.EndUpdate;
This magic is possible via Reflection:
public static class Helper{
public static bool IsNotImplementedMember(this MemberInfo me)
{
switch (me)
{
case MethodInfo mi:
var mb = mi.GetMethodBody();
if (mb == null) return true;
if (mb.ExceptionHandlingClauses.Any()) return false;
if (mb.InitLocals) return false;
if (mb.LocalVariables.Any()) return false;
var il = mb.GetILAsByteArray().SkipWhile(b => b == 0).ToArray();
if (il.Length != 6) return false;
return (il[0] == 115) && (il[5] == 122);
case PropertyInfo pro:
return IsNotImplementedGetter(pro);
default:
return false;
}
}
public static bool IsNotImplementedGetter(this PropertyInfo mi)
{
var m = mi.GetGetMethod();
if (m == null) return true;
return m.IsNotImplementedMember();
}
public static bool IsNotImplementedSetter(this PropertyInfo mi)
{
var m = mi.GetSetMethod();
if (m == null) return true;
return m.IsNotImplementedMember();
}
public static bool IsNotImplemented
(Type t, string name, bool @public = true, bool instance = true)
{
BindingFlags b = (@public ? BindingFlags.Public :
BindingFlags.NonPublic) |
(instance ? BindingFlags.Instance : BindingFlags.Static);
var m = t.GetMember(name, b);
if (!m.Any()) return false;
if (m.Length != 1) throw new ArgumentException
("More than one member same name");
return IsNotImplementedMember(m[0]);
}
public static bool IsNotImplemented<T>
(string name, bool @public = true, bool instance = true)
{
return IsNotImplemented(typeof(T), name, @public, instance);
}
public static bool IsNotImplemented<T>
(this T obj,string name, bool @public = true, bool instance = true)
{
return IsNotImplemented(obj.GetType(), name, @public, instance);
}
public static bool IsNotImplemented<T>(Expression<Action<T>> expression)
{
var me = ExtractMember(expression);
return IsNotImplemented<T>(me.Name);
}
public static bool IsNotImplemented<T>
(this T obj,Expression<Action<T>> expression)
{
var me = ExtractMember(expression);
return IsNotImplemented<T>(me.Name);
}
}
This Extension Helper Class has several entry points. I use "nameof(...)
" but there are other ways.
Points of Interest
As simple as checking IL implementation. Instead, I would have preferred default interface implementations but, at the current time, C# lacks this.
History