How to change a target using Castle DynamicProxy - c#

I am trying to understand Castle's DynamicProxy and the thing I would like to do is to change the target of the generated proxy at runtime.
Something like this...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
namespace ConsoleApplication16
{
class Program
{
static void Main(string[] args)
{
IFoo foo = new Foo("Foo 1");
IFoo foo2 = new Foo("Foo 2");
foo.DoSomething("Hello!");
ProxyGenerator generator = new ProxyGenerator();
IFoo proxiedFoo = generator.CreateInterfaceProxyWithTarget<IFoo>(foo);
proxiedFoo.DoSomething("Hello proxied!");
(proxiedFoo as IChangeProxyTarget).ChangeProxyTarget(foo2); // cast results in null reference
proxiedFoo.DoSomething("Hello!");
}
}
}
I thought the generated proxy would implement IChangeProxyTarget but the cast to the interface results in a null reference.
How can I change the target of a generated proxy at runtime?
Update As mentioned in an answer, I tried using CreateInterfaceProxyWithTargetInterface and I'm still unable to cast to IChangeProxyTarget to change the target.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
namespace ConsoleApplication16
{
class Program
{
static void Main(string[] args)
{
IFoo foo = new Foo("Foo 1");
IFoo foo2 = new Foo("Foo 2");
foo.DoSomething("Hello!");
ProxyGenerator generator = new ProxyGenerator();
IFoo proxiedFoo = generator.CreateInterfaceProxyWithTargetInterface<IFoo>(foo);
proxiedFoo.DoSomething("Hello proxied!");
IChangeProxyTarget changeProxyTarget = proxiedFoo as IChangeProxyTarget;
if (changeProxyTarget == null) // always null...
{
Console.WriteLine("Failed");
return;
}
changeProxyTarget.ChangeProxyTarget(foo2);
proxiedFoo.DoSomething("Hello!");
}
}
}

use CreateInterfaceProxyWithTargetInterface
That one will allow you to change the proxy/invocation target.
Also the IChangeProxyTarget is implemented by invocation type, not the proxy itself.

Related

LightInject - Derived interfaces leads to multiple instances

In my application I handle lots of ViewModels that get registered inside a LightInject Container via several Interfaces. Some of those Interfaces are derived from other for UnitTesting purposes.
When resolving multiple ViewModels with the same Interface that is an interface further above I get more ViewModelinstances than expected.
I made a simplified example for this behavior. Is it possible to prevent this behavior somehow?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public interface IBar
{
}
public interface IFoo : IBar
{
}
public class Cat : IFoo
{
}
class Program
{
static void Main(string[] args)
{
var container = new LightInject.ServiceContainer();
container.Register<IBar, Cat>();
container.Register<IFoo, Cat>();
var m = container.GetAllInstances(typeof(IBar));
// m will contain 2 Instances of Cat. Is it possible it will resolve only 1 Instance?
}
}
}
Try this
var container = new ServiceContainer(new ContainerOptions() {EnableVariance = false});

Checking whether all my classes have the Serializable attribute

In my current software I make use of serialization and therefore need everything to be marked with the [Serializable] attribute.
Is there an easy way of checking this using my Visual Studio without going through them one at a time, or just waiting for it to crash?
To clarify, I don't need to know how to check if a class is serializable in code. I'm talking about using the IDE.
If you want to use reflection to find classes not marked [Serializable] you can use reflection to get the class types via GetTypes and then find only those not marked with Serializable.
try this:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ReflectOnSerializableAttr
{
class Program
{
static void Main(string[] args)
{
//use Linq
var q = from t in Assembly.GetExecutingAssembly().GetTypes()
where t.IsClass && ((t.Attributes & TypeAttributes.Serializable) != TypeAttributes.Serializable)
select t;
q.ToList().ForEach(t => Console.WriteLine(t.Name));
Console.ReadKey();
}
}
[Serializable]
public class TestSerializableOne
{
public string SomeFunc() { return "somefunc"; }
}
public class TestForgotSerializable
{
private int _testInt = 200;
}
}
The above program outputs:
Program
TestForgotSerializable

TypedParameter is not used if the type is already register

I have an unexpected behavior of the TypedParameter in Autofac. It ignored if the type is already register and I don't know if is it correct or how to obtain the expected behavior. Example:
I have a Foo class with the following constructor.
public class Foo
{
public Foo(IEnumerable<IRule> rules)
{..}
}
I've already register a lot of rules inside the builder (scanning the assembly), but when I resolve, I would like to pass an Autofac TypedParameter with a custom list of IRules
TypedParameter iocParam = new TypedParameter(typeof(IEnumerable<IRule>), rules);
var result = container.Resolve(FOO, iocParam);
The problem here is Autofac is ignoring myCustomListOfRules and creating a list with all available IRules already register in first place, instead of using the TypedParameter.
If I use a NamedParameter:
NamedParameter iocParam = new NamedParameter("rules", myCustomListOfRules);
works fine, but I have to hardcode the name of the parameter instead of resolve it by the type.
Is it correct the behavior of the TypedParameter or there is a way to use it as I want?
Update:
I was doing something else bad because the TypedParameter has the expected behavior. The following example works as expected.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autofac;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Rule1>().As<IRule>();
builder.RegisterType<Rule2>().As<IRule>();
builder.RegisterType<Foo>();
var resolver=builder.Build();
// autofac resolve foo with all of available rules, ok¡
var foo1=resolver.Resolve<Foo>();
Console.WriteLine(foo1.GetNumberOfRules());
// resolve with custom rules, ok¡
var rules=new List<IRule>();
rules.Add(new Rule1());
TypedParameter param = new TypedParameter(typeof(IEnumerable<IRule>), rules);
var foo2 = resolver.Resolve<Foo>(param);
Console.WriteLine(foo2.GetNumberOfRules());
Console.ReadLine();
}
}
public class Foo
{
IEnumerable<IRule> rules;
public Foo(IEnumerable<IRule> rules)
{
this.rules = rules;
}
public int GetNumberOfRules()
{
return this.rules.Count();
}
}
public interface IRule
{
}
public class Rule1 : IRule
{
}
public class Rule2 : IRule
{
}
}

Commenting namespaces doesn't affect the ToString() method

Today someone showed me a code snippet and I am wondering how its working:
//using System;
//using System.Collections.Generic;
//using System.Text;
namespace ConsoleApplication1
{
class Test
{
int i = 0;
}
class Program
{
static void Main(string[] args)
{
Test obj = new Test();
obj.ToString();
}
}
}
My question is if we have commented the above namespaces, how is the ToString() method still associated to the object obj?
Every class in C# inherits Object class, in which ToString is defined

How to correct warning CS1707?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Collections;
using System.ComponentModel;
namespace ConsoleApplication1
{
class BreakingChange
{
delegate void SampleDelegate(string x);
public void CandidateAction(string x)
{
Console.WriteLine("Snippet.CandidateAction");
}
public class Derived : BreakingChange
{
public void CandidateAction(object o)
{
Console.WriteLine("Derived.CandidateAction");
}
}
static void Main()
{
Derived x = new Derived();
SampleDelegate factory = new SampleDelegate(x.CandidateAction);
factory("test");
}
}
}
\Program.cs(32,38): warning CS1707: Delegate 'ConsoleApplication1.BreakingChange.SampleDelegate' bound to 'ConsoleApplication1.BreakingChange.Derived.CandidateAction(object)' instead of 'ConsoleApplication1.BreakingChange.CandidateAction(string)' because of new language rules
\Program.cs(23,25): (Related location)
\Program.cs(16,21): (Related location)
Question:
I know what causes this warning and know the reason behind it. However, I don't know what the
best way to fix it?
1> Redefine the function (i.e.) change the function signature
2> Can we explicitly call BreakingChange.CandidateAction in the following line?
SampleDelegate factory = new SampleDelegate(x.CandidateAction);
Well, there are multiple ways to "fix" this, depending on what you want to, and can, do.
Personally I would add another overload to Derived that took a string, since you're going to have the same issue with non-delegate calls as well.
public class Derived : BreakingChange
{
public new void CandidateAction(string x)
{
base.CandidateAction(x);
}
public void CandidateAction(object o)
{
Console.WriteLine("Derived.CandidateAction");
}
}
Or, since you know you want the base class method, you can cast the reference x:
new SampleDelegate(((BreakingChange)x).CandidateAction)

Categories

Resources