我正在尝试使用Unity在不接触现有代码库的情况下在对象顶部添加接口。
这里的目标是通过在我的应用程序中简单地配置现有的代码库,将一些拦截器应用于现有的代码基。
需要牢记的事项:
- 我知道我可以将接口应用于所有必要的类。我只是想知道是否有可能在运行时使用我的Unity配置来应用所有这些,而不是修改所有现有的代码
- 在这种特殊情况下,拦截器实际上只是一个直通,我希望生成的虚拟代理具有我的IWhatever接口所需的必要属性
- 我提供的代码抛出了一个NotImplementedException,但据我所知,"Name"属性应该已经注入到代理中
这里有一个代码示例:
public class Program
{
public static void Main(string[] args)
{
IUnityContainer container = new UnityContainer()
.AddNewExtension<Interception>();
container.RegisterType<ICat, Cat>(
new InjectionMember[]
{
new AdditionalInterface<IWhatever>(),
new InjectionProperty("Name",""), //checking to see if this will fix our IWhatever injection problem
new Interceptor<VirtualMethodInterceptor>(),
new InterceptionBehavior<VirPropInterceptorBehavior>()
}
);
ICat c = container.Resolve<ICat>();
string propVal = ((IWhatever)c).Name;
Console.Read();
}
}
public interface IWhatever
{
void DoWhatever();
string Name { get; set; }
}
public interface ICat
{
}
public class Cat : IAuditable, ICat
{
public int Age { get; set; }
public string Name { get; set; }
}
public class VirPropInterceptorBehavior : IInterceptionBehavior
{
private object propVal;
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
return getNext()(input, getNext);
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return new[] { typeof(IWhatever) };
}
public bool WillExecute
{
get { return false; }
}
}
您有两个问题。首先,Cat没有提供IWhatever
的实现——尽管它有Name
,但这不是IWhatever
的Name
的实现。在Cat上找不到它。你可以这样做,但注意它终止了拦截器链:
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
if (input.MethodBase.DeclaringType == typeof (IWhatever)
&& input.MethodBase.Name == "get_Name")
{
return input.CreateMethodReturn(((Cat) (input.Target)).Name);
}
return getNext()(input, getNext);
}
也许您想将Name存储在Cat对象之外的其他地方——也许是在针对对象实例的Dictionary中(想想DependencyProperty
系统在WPF中是如何工作的)。
第二个问题是…你会踢自己。。。您需要WillExecute
返回true
才能运行拦截器。
实际上,您必须在您的行为VirPropInterceptorBehavior中编写IWhatever's Name的实现。请参阅https://unity.codeplex.com/discussions/227719详细信息。
但问题仍然存在,如何处理这种情况?在您的行为中,您必须识别对IWhatever.Name的调用,并在那里实现它(在行为的Invoke方法中)。你可以这样做。我只为GET实现了,您可以为setter实现。
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
IMethodReturn result;
// Taking care of implementation of additional interface IWhatever.
if (input.MethodBase.DeclaringType == typeof (IWhatever))
{
switch (input.MethodBase.Name)
{
case "get_Name":
// Do your stuff here
// Make sure you do this to get rid of your exception.
// Pass the argument so that the calling code gets it.
result = input.CreateMethodReturn(input.Arguments[0]);
break;
default:
result = input.CreateMethodReturn(null);
break;
}
}
else
{
// Do other stuff here.
result = getNext()(input, getNext);
}
return result;
}
我希望它能帮助你。