Can you hack this out? Revised
It appears that I made this challenge a bit too hard, I wrote it in haste and didn’t check that it all works. Here is the new code, it is almost the same as the first, but now it doesn’t check the typeof(T) (for which there is no interception path), but the provided runnerType instead.
internal interface IRunner
{
void Execute();
}
public sealed class AssemblyRunner : IRunner
{
void IRunner.Execute()
{
Console.WriteLine("executing");
}
}
public class CompositeRunner
{
private readonly Type runnerType;
public CompositeRunner(Type runnerType)
{
this.runnerType = runnerType;
}
public void Execute()
{
if (!typeof(IRunner).IsAssignableFrom(runnerType))
throw new InvalidOperationException("invalid type");
var runner = (IRunner)Activator.CreateInstance(runnerType);
Console.WriteLine("starting");
runner.Execute();
Console.WriteLine("done");
}
}
Look at the future posts for hints for that.
Comments
Now THAT'S easy!
I have a great solution for this, but it doesn't fit in this comment. :-)
OK. You already forced me to look at ProfilingSqlProviderProxyType, so I cannot participate.
tdanecker.blogspot.com/.../...on-with-proxies.html :p
[)amien
Omar,
Pierre
now it seems almost simple. you can create a RealProxy for IRunner
class MyProxy : RealProxy {
MyProxy() : base (Type.GetType ("IRunner...")
and put a custom ProxyAttribute on the type you pass (must be derived from ContextBoundObject). Some fumbling with Invoke(), that should basically be it...
Stefan,
Write the code, there is still one trip wire there.
The one trip still there is the " if (!typeof(IRunner).IsAssignableFrom(runnerType))" check.
And this can be solved by:
subclassing System.Type (in actual C# code, no hackery required) and
overriding UnderlyingType
to return typeof (IRunner) on the first call and
typeof (MyContextBoundObject) on the second call.
Strangely, this works, it really does. At the moment, at least. Aren't you afraid to actually sell a piece of software based on this hack? :)
("trip wire", of course)
Fabian,
I am really scared by that, yes.
OTOH, what other choice do I have?
CreateInstance(Of T) that is. No angle brackets, must be a VB lover's blog ;-)
BTW, just when I realized that R# can't go all the way when subclassing Type via delegation to a member, I discoverd System.Reflection.TypeDelegator. Nice!
Insanely, I agree with you Ayende. If this changes in vNext, you'll just have to come up with another unnatural hack. Still better than Profiling APIs by any means.
Yes, this looks more doable.
@Omer nice Fermat analogy there :)
This hack just goes to show that there is no true privacy in such a system, simplest example being how easy it is to instantiate a type through a private constructor. I wonder how the CLR would want to avoid such things from happening. After all it needs to interrogate the type to answer whether it is assignable and Type is an abstract class in which you can override stuff.
I CAN'T TAKE IT ANYMORE! I've spent too many hours on this already... well, ok... only 2.5, but that is too many for me.
Once Fabian suggested deriving from Type, I got past the IsAssignableFrom... And I'm using ContextBoundObject to return a RealProxy from Activator.CreateInstance, but I cannot get past the unable to cast transparent proxy to type IRunner
What is the solution?
Jay, implement IRemotingTypeInfo on your real proxy, then the cast isn't an issue any longer.
Fabian,
Thanks. I had that, but removed it when I went with a different approach.
... I'm learning WAY too much here :)
I tried to implement the solution according to the comments, but I still fail to get past the "unable to cast transparent proxy" part.
Can you give me a hint?
This is my solution so far:
public class Program
{
<assemblyrunner();
}
public class MyProxyAttribute : ProxyAttribute
{
}
[MyProxy]
public class MySubclass : ContextBoundObject
{
}
public class MyType{T} : TypeDelegator
{
}
public class MyProxy : RealProxy, IRemotingTypeInfo
{
}
Check how it is done, here:
cid-0c0c3706a4965f47.skydrive.live.com/.../....zip
Done it, so as hard as I thought.
This challenge suddenly much easier without the generic type.
Basically, I use:
TypeDelegator to pass IsAssignableFrom
ContextBoundObject, ProxyAttribute and RealProxy to create an interceptor for the instance.
IRemotingTypeInfo to pass the type casting check.
All method call are then redirected to the real runner.
I don't see any chance that there will be any change that will cause this code not to run in next versions of .NET Framework.
TypeDelegator is used for the purpose it was created, that is delegating the type information.
Proxy is used to redirect messages, which is also what it was created for.
The only place that I used a real hack is in the GetInterfaces of TypeDelegator when I use StackFrame to see who called the method to return the appropriate result.
So there is no solution for the original one? I was really curious on how you hacked the typeof(T) :P
Alk.
Comment preview