diff --git a/src/DivertR/DiverterSettings.cs b/src/DivertR/DiverterSettings.cs
index 8589b5e2..505e8c69 100644
--- a/src/DivertR/DiverterSettings.cs
+++ b/src/DivertR/DiverterSettings.cs
@@ -1,7 +1,5 @@
 using DivertR.DispatchProxy;
 using DivertR.Dummy;
-using DivertR.Dummy.Internal;
-using DivertR.Internal;
 
 namespace DivertR
 {
@@ -15,10 +13,8 @@ public class DiverterSettings
         public bool DefaultWithDummyRoot { get; }
 
         public IDummyFactory DummyFactory { get; }
-        
-        public IRedirectRepository DummyRedirectRepository { get; }
 
-        
+
         public static DiverterSettings Global
         {
             get
@@ -41,20 +37,11 @@ public static DiverterSettings Global
         public DiverterSettings(
             IProxyFactory? proxyFactory = null,
             bool defaultWithDummyRoot = true,
-            IRedirectRepository? dummyRedirectRepository = null,
-            IDummyFactory? defaultRootFactory = null)
+            IDummyFactory? dummyFactory = null)
         {
             ProxyFactory = proxyFactory ?? new DispatchProxyFactory();
             DefaultWithDummyRoot = defaultWithDummyRoot;
-            DummyRedirectRepository = dummyRedirectRepository ?? CreateDummyRepository();
-            DummyFactory = defaultRootFactory ?? new DummyFactory();
-        }
-
-        private static IRedirectRepository CreateDummyRepository()
-        {
-            var redirect = new Redirect(new DummyCallHandler());
-            
-            return new RedirectRepository(new[] { redirect });
+            DummyFactory = dummyFactory ?? new DummyFactory();
         }
     }
 }
\ No newline at end of file
diff --git a/src/DivertR/Dummy/DummyFactory.cs b/src/DivertR/Dummy/DummyFactory.cs
new file mode 100644
index 00000000..b672c334
--- /dev/null
+++ b/src/DivertR/Dummy/DummyFactory.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Linq.Expressions;
+using DivertR.Dummy.Internal;
+using DivertR.Internal;
+
+namespace DivertR.Dummy
+{
+    public class DummyFactory : IDummyFactory
+    {
+        public DummyFactory()
+        {
+            var redirect = new Redirect(new DummyCallHandler());
+            RedirectRepository = new RedirectRepository(new[] { redirect });
+        }
+        
+        public DummyFactory(IRedirectRepository redirectRepository)
+        {
+            RedirectRepository = redirectRepository;
+        }
+
+        public TTarget Create<TTarget>(DiverterSettings diverterSettings) where TTarget : class
+        {
+            var via = new Via<TTarget>(diverterSettings, RedirectRepository);
+
+            return via.Proxy(false);
+        }
+        
+        public IRedirectRepository RedirectRepository { get; }
+        
+        public IDummyBuilder<TReturn> To<TReturn>(Expression<Func<TReturn>> constraintExpression)
+        {
+            var redirectBuilder = RedirectBuilder.To(constraintExpression);
+
+            return new DummyBuilder<TReturn>(RedirectRepository, redirectBuilder);
+        }
+
+        public IDummyBuilder To(ICallConstraint? callConstraint = null)
+        {
+            var redirectBuilder = RedirectBuilder.To(callConstraint);
+
+            return new DummyBuilder(RedirectRepository, redirectBuilder);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/DivertR/Dummy/IDummyBuilder.cs b/src/DivertR/Dummy/IDummyBuilder.cs
new file mode 100644
index 00000000..1ac8d3c3
--- /dev/null
+++ b/src/DivertR/Dummy/IDummyBuilder.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace DivertR.Dummy
+{
+    public interface IDummyBuilder<TReturn>
+    {
+        IDummyBuilder<TReturn> AddConstraint(ICallConstraint callConstraint);
+        IDummyBuilder<TReturn> Redirect(TReturn instance, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IDummyBuilder<TReturn> Redirect(Func<TReturn> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IDummyBuilder<TReturn> Redirect(Func<IFuncRedirectCall<TReturn>, TReturn> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IDummyBuilder<TReturn> Redirect(Func<IFuncRedirectCall<TReturn>, CallArguments, TReturn> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
+    }
+    
+    public interface IDummyBuilder
+    {
+        IDummyBuilder AddConstraint(ICallConstraint callConstraint);
+        IDummyBuilder Redirect(object instance, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IDummyBuilder Redirect(Func<object> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IDummyBuilder Redirect(Func<IRedirectCall, object> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IDummyBuilder Redirect(Func<IRedirectCall, CallArguments, object> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
+    }
+}
\ No newline at end of file
diff --git a/src/DivertR/Dummy/Internal/DummyBuilder.cs b/src/DivertR/Dummy/Internal/DummyBuilder.cs
new file mode 100644
index 00000000..55a0e0e2
--- /dev/null
+++ b/src/DivertR/Dummy/Internal/DummyBuilder.cs
@@ -0,0 +1,106 @@
+using System;
+
+namespace DivertR.Dummy.Internal
+{
+    internal class DummyBuilder<TReturn> : IDummyBuilder<TReturn>
+    {
+        private readonly IRedirectRepository _redirectRepository;
+        private readonly IFuncRedirectBuilder<TReturn> _redirectBuilder;
+
+        public DummyBuilder(IRedirectRepository redirectRepository, IFuncRedirectBuilder<TReturn> redirectBuilder)
+        {
+            _redirectRepository = redirectRepository;
+            _redirectBuilder = redirectBuilder;
+        }
+        
+        public IDummyBuilder<TReturn> AddConstraint(ICallConstraint callConstraint)
+        {
+            _redirectBuilder.AddConstraint(callConstraint);
+
+            return this;
+        }
+
+        public IDummyBuilder<TReturn> Redirect(TReturn instance, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var redirect = _redirectBuilder.Build(instance, optionsAction);
+            _redirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IDummyBuilder<TReturn> Redirect(Func<TReturn> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var redirect = _redirectBuilder.Build(redirectDelegate, optionsAction);
+            _redirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IDummyBuilder<TReturn> Redirect(Func<IFuncRedirectCall<TReturn>, TReturn> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var redirect = _redirectBuilder.Build(redirectDelegate, optionsAction);
+            _redirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IDummyBuilder<TReturn> Redirect(Func<IFuncRedirectCall<TReturn>, CallArguments, TReturn> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var redirect = _redirectBuilder.Build(redirectDelegate, optionsAction);
+            _redirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+    }
+    
+    internal class DummyBuilder : IDummyBuilder
+    {
+        private readonly IRedirectRepository _redirectRepository;
+        private readonly IRedirectBuilder _redirectBuilder;
+
+        public DummyBuilder(IRedirectRepository redirectRepository, IRedirectBuilder redirectBuilder)
+        {
+            _redirectRepository = redirectRepository;
+            _redirectBuilder = redirectBuilder;
+        }
+        
+        public IDummyBuilder AddConstraint(ICallConstraint callConstraint)
+        {
+            _redirectBuilder.AddConstraint(callConstraint);
+
+            return this;
+        }
+
+        public IDummyBuilder Redirect(object instance, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var redirect = _redirectBuilder.Build(instance, optionsAction);
+            _redirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IDummyBuilder Redirect(Func<object> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var redirect = _redirectBuilder.Build(redirectDelegate, optionsAction);
+            _redirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IDummyBuilder Redirect(Func<IRedirectCall, object> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var redirect = _redirectBuilder.Build(redirectDelegate, optionsAction);
+            _redirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IDummyBuilder Redirect(Func<IRedirectCall, CallArguments, object> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var redirect = _redirectBuilder.Build(redirectDelegate, optionsAction);
+            _redirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/DivertR/Dummy/Internal/DummyFactory.cs b/src/DivertR/Dummy/Internal/DummyFactory.cs
deleted file mode 100644
index 2358955d..00000000
--- a/src/DivertR/Dummy/Internal/DummyFactory.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace DivertR.Dummy.Internal
-{
-    internal class DummyFactory : IDummyFactory
-    {
-        public TTarget Create<TTarget>(DiverterSettings diverterSettings) where TTarget : class
-        {
-            var via = new Via<TTarget>(diverterSettings, diverterSettings.DummyRedirectRepository);
-
-            return via.Proxy(false);
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/DivertR/IActionViaBuilder.cs b/src/DivertR/IActionViaBuilder.cs
index c4273a49..60b454e4 100644
--- a/src/DivertR/IActionViaBuilder.cs
+++ b/src/DivertR/IActionViaBuilder.cs
@@ -4,13 +4,13 @@
 
 namespace DivertR
 {
-    public interface IActionViaBuilder<TTarget> : IDelegateViaBuilder<TTarget> where TTarget : class
+    public interface IActionViaBuilder<TTarget> : IViaBuilder<TTarget> where TTarget : class
     {
         new IActionRedirectBuilder<TTarget> RedirectBuilder { get; }
         
         new IActionViaBuilder<TTarget> AddConstraint(ICallConstraint<TTarget> callConstraint);
 
-        new IActionViaBuilder<TTarget> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IActionViaBuilder<TTarget> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IActionViaBuilder<TTarget> Redirect(Action redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IActionViaBuilder<TTarget> Redirect(Action<IActionRedirectCall<TTarget>> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IActionViaBuilder<TTarget> Redirect(Action<IActionRedirectCall<TTarget>, CallArguments> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
diff --git a/src/DivertR/IDelegateViaBuilder.cs b/src/DivertR/IDelegateViaBuilder.cs
deleted file mode 100644
index bfbf7bdc..00000000
--- a/src/DivertR/IDelegateViaBuilder.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace DivertR
-{
-    public interface IDelegateViaBuilder<TTarget> : IViaBuilder<TTarget> where TTarget : class
-    {
-        new IDelegateRedirectBuilder<TTarget> RedirectBuilder { get; }
-        
-        IDelegateViaBuilder<TTarget> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
-    }
-}
diff --git a/src/DivertR/IFuncViaBuilder.cs b/src/DivertR/IFuncViaBuilder.cs
index 113cc706..b521c7d7 100644
--- a/src/DivertR/IFuncViaBuilder.cs
+++ b/src/DivertR/IFuncViaBuilder.cs
@@ -4,13 +4,13 @@
 
 namespace DivertR
 {
-    public interface IFuncViaBuilder<TTarget, TReturn> : IDelegateViaBuilder<TTarget> where TTarget : class
+    public interface IFuncViaBuilder<TTarget, TReturn> : IViaBuilder<TTarget> where TTarget : class
     {
         new IFuncRedirectBuilder<TTarget, TReturn> RedirectBuilder { get; }
         
         new IFuncViaBuilder<TTarget, TReturn> AddConstraint(ICallConstraint<TTarget> callConstraint);
 
-        new IFuncViaBuilder<TTarget, TReturn> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IFuncViaBuilder<TTarget, TReturn> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IFuncViaBuilder<TTarget, TReturn> Redirect(TReturn instance, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IFuncViaBuilder<TTarget, TReturn> Redirect(Func<TReturn> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IFuncViaBuilder<TTarget, TReturn> Redirect(Func<IFuncRedirectCall<TTarget, TReturn>, TReturn> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
diff --git a/src/DivertR/IRedirectBuilder.cs b/src/DivertR/IRedirectBuilder.cs
index bb758c2c..57a6772e 100644
--- a/src/DivertR/IRedirectBuilder.cs
+++ b/src/DivertR/IRedirectBuilder.cs
@@ -6,7 +6,10 @@ namespace DivertR
     public interface IRedirectBuilder<TTarget> where TTarget : class
     {
         IRedirectBuilder<TTarget> AddConstraint(ICallConstraint<TTarget> callConstraint);
-        IRedirect Build(TTarget target, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IRedirect Build(object? instance, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IRedirect Build(Func<object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IRedirect Build(Func<IRedirectCall<TTarget>, object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IRedirect Build(Func<IRedirectCall<TTarget>, CallArguments, object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IRedirect Build(ICallHandler<TTarget> callHandler, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IRedirect Build(ICallHandler<TTarget> callHandler, IRedirectOptions redirectOptions);
         IRecordRedirect<TTarget> Record(Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
@@ -15,7 +18,10 @@ public interface IRedirectBuilder<TTarget> where TTarget : class
     public interface IRedirectBuilder
     {
         IRedirectBuilder AddConstraint(ICallConstraint callConstraint);
-        IRedirect Build(object target, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IRedirect Build(object? instance, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IRedirect Build(Func<object?> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IRedirect Build(Func<IRedirectCall, object?> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
+        IRedirect Build(Func<IRedirectCall, CallArguments, object?> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null);
         IRedirect Build(ICallHandler callHandler, Action<IRedirectOptionsBuilder>? optionsAction = null);
         IRedirect Build(ICallHandler callHandler, IRedirectOptions redirectOptions);
         IRecordRedirect Record(Action<IRedirectOptionsBuilder>? optionsAction = null);
diff --git a/src/DivertR/IViaBuilder.cs b/src/DivertR/IViaBuilder.cs
index 7a91abf7..3c35756a 100644
--- a/src/DivertR/IViaBuilder.cs
+++ b/src/DivertR/IViaBuilder.cs
@@ -9,6 +9,10 @@ public interface IViaBuilder<TTarget> where TTarget : class
         IRedirectBuilder<TTarget> RedirectBuilder { get; }
         
         IViaBuilder<TTarget> AddConstraint(ICallConstraint<TTarget> callConstraint);
+        IViaBuilder<TTarget> Redirect(object? instance, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IViaBuilder<TTarget> Redirect(Func<object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IViaBuilder<TTarget> Redirect(Func<IRedirectCall<TTarget>, object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
+        IViaBuilder<TTarget> Redirect(Func<IRedirectCall<TTarget>, CallArguments, object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IViaBuilder<TTarget> Retarget(TTarget target, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
         IRecordStream<TTarget> Record(Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null);
     }
diff --git a/src/DivertR/Internal/ActionViaBuilder.cs b/src/DivertR/Internal/ActionViaBuilder.cs
index 0052a9fb..9f2608c6 100644
--- a/src/DivertR/Internal/ActionViaBuilder.cs
+++ b/src/DivertR/Internal/ActionViaBuilder.cs
@@ -4,7 +4,7 @@
 
 namespace DivertR.Internal
 {
-    internal class ActionViaBuilder<TTarget> : DelegateViaBuilder<TTarget>, IActionViaBuilder<TTarget> where TTarget : class
+    internal class ActionViaBuilder<TTarget> : ViaBuilder<TTarget>, IActionViaBuilder<TTarget> where TTarget : class
     {
         public ActionViaBuilder(IVia<TTarget> via, IActionRedirectBuilder<TTarget> redirectBuilder)
             : base(via, redirectBuilder)
@@ -21,9 +21,10 @@ public ActionViaBuilder(IVia<TTarget> via, IActionRedirectBuilder<TTarget> redir
             return this;
         }
         
-        public new IActionViaBuilder<TTarget> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        public IActionViaBuilder<TTarget> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
         {
-            base.Redirect(redirectDelegate, optionsAction);
+            var redirect = RedirectBuilder.Build(redirectDelegate, optionsAction);
+            Via.RedirectRepository.InsertRedirect(redirect);
 
             return this;
         }
diff --git a/src/DivertR/Internal/DelegateViaBuilder.cs b/src/DivertR/Internal/DelegateViaBuilder.cs
deleted file mode 100644
index df11f285..00000000
--- a/src/DivertR/Internal/DelegateViaBuilder.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-
-namespace DivertR.Internal
-{
-    internal abstract class DelegateViaBuilder<TTarget> : ViaBuilder<TTarget>, IDelegateViaBuilder<TTarget> where TTarget : class
-    {
-        protected DelegateViaBuilder(IVia<TTarget> via, IDelegateRedirectBuilder<TTarget> redirectBuilder)
-            : base(via, redirectBuilder)
-        {
-            RedirectBuilder = redirectBuilder;
-        }
-
-        public new IDelegateRedirectBuilder<TTarget> RedirectBuilder { get; }
-
-        public IDelegateViaBuilder<TTarget> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
-        {
-            var redirect = RedirectBuilder.Build(redirectDelegate, optionsAction);
-            Via.RedirectRepository.InsertRedirect(redirect);
-
-            return this;
-        }
-    }
-}
diff --git a/src/DivertR/Internal/FuncViaBuilder.cs b/src/DivertR/Internal/FuncViaBuilder.cs
index b553a80c..20278462 100644
--- a/src/DivertR/Internal/FuncViaBuilder.cs
+++ b/src/DivertR/Internal/FuncViaBuilder.cs
@@ -4,7 +4,7 @@
 
 namespace DivertR.Internal
 {
-    internal class FuncViaBuilder<TTarget, TReturn> : DelegateViaBuilder<TTarget>, IFuncViaBuilder<TTarget, TReturn> where TTarget : class
+    internal class FuncViaBuilder<TTarget, TReturn> : ViaBuilder<TTarget>, IFuncViaBuilder<TTarget, TReturn> where TTarget : class
     {
         public FuncViaBuilder(IVia<TTarget> via, IFuncRedirectBuilder<TTarget, TReturn> redirectBuilder)
             : base(via, redirectBuilder)
@@ -21,9 +21,10 @@ public FuncViaBuilder(IVia<TTarget> via, IFuncRedirectBuilder<TTarget, TReturn>
             return this;
         }
 
-        public new IFuncViaBuilder<TTarget, TReturn> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        public IFuncViaBuilder<TTarget, TReturn> Redirect(Delegate redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
         {
-            base.Redirect(redirectDelegate, optionsAction);
+            var redirect = RedirectBuilder.Build(redirectDelegate, optionsAction);
+            Via.RedirectRepository.InsertRedirect(redirect);
 
             return this;
         }
diff --git a/src/DivertR/Internal/RedirectBuilder.cs b/src/DivertR/Internal/RedirectBuilder.cs
index 05a63b8b..8cbd1987 100644
--- a/src/DivertR/Internal/RedirectBuilder.cs
+++ b/src/DivertR/Internal/RedirectBuilder.cs
@@ -23,13 +23,30 @@ public IRedirectBuilder<TTarget> AddConstraint(ICallConstraint<TTarget> callCons
             return this;
         }
 
-        public IRedirect Build(TTarget target, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        public IRedirect Build(object? instance, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
         {
-            ICallHandler<TTarget> callHandler = new TargetCallHandler<TTarget>(target);
+            return Build(call => instance, optionsAction);
+        }
+
+        public IRedirect Build(Func<object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        {
+            return Build(call => redirectDelegate.Invoke(), optionsAction);
+        }
 
+        public IRedirect Build(Func<IRedirectCall<TTarget>, object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        {
+            var callHandler = new RedirectCallHandler<TTarget>(redirectDelegate);
+            
             return Build(callHandler, optionsAction);
         }
-        
+
+        public IRedirect Build(Func<IRedirectCall<TTarget>, CallArguments, object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        {
+            var callHandler = new RedirectArgsCallHandler<TTarget>(redirectDelegate);
+            
+            return Build(callHandler, optionsAction);
+        }
+
         public IRedirect Build(ICallHandler<TTarget> callHandler, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
         {
             var builder = new RedirectOptionsBuilder<TTarget>();
@@ -58,7 +75,7 @@ public IRecordRedirect<TTarget> Record(Action<IRedirectOptionsBuilder<TTarget>>?
     
     internal class RedirectBuilder : IRedirectBuilder
     {
-        protected CompositeCallConstraint CallConstraint { get; private set; } = CompositeCallConstraint.Empty;
+        private CompositeCallConstraint CallConstraint { get; set; } = CompositeCallConstraint.Empty;
 
         public RedirectBuilder(ICallConstraint? callConstraint = null)
         {
@@ -75,13 +92,30 @@ public IRedirectBuilder AddConstraint(ICallConstraint callConstraint)
             return this;
         }
 
-        public IRedirect Build(object target, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        public IRedirect Build(object? instance, Action<IRedirectOptionsBuilder>? optionsAction = null)
         {
-            var callHandler = new TargetCallHandler(target);
+            return Build(call => instance, optionsAction);
+        }
+
+        public IRedirect Build(Func<object?> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            return Build(call => redirectDelegate.Invoke(), optionsAction);
+        }
 
+        public IRedirect Build(Func<IRedirectCall, object?> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var callHandler = new RedirectCallHandler(redirectDelegate);
+            
             return Build(callHandler, optionsAction);
         }
-        
+
+        public IRedirect Build(Func<IRedirectCall, CallArguments, object?> redirectDelegate, Action<IRedirectOptionsBuilder>? optionsAction = null)
+        {
+            var callHandler = new RedirectArgsCallHandler(redirectDelegate);
+            
+            return Build(callHandler, optionsAction);
+        }
+
         public IRedirect Build(ICallHandler callHandler, Action<IRedirectOptionsBuilder>? optionsAction = null)
         {
             var builder = new RedirectOptionsBuilder();
diff --git a/src/DivertR/Internal/RedirectCallHandler.cs b/src/DivertR/Internal/RedirectCallHandler.cs
index bd0ad2f6..0ee75b14 100644
--- a/src/DivertR/Internal/RedirectCallHandler.cs
+++ b/src/DivertR/Internal/RedirectCallHandler.cs
@@ -5,9 +5,9 @@ namespace DivertR.Internal
 {
     internal class RedirectCallHandler<TTarget> : ICallHandler<TTarget> where TTarget : class
     {
-        private readonly Action<IRedirectCall<TTarget>> _redirectDelegate;
+        private readonly Func<IRedirectCall<TTarget>, object?> _redirectDelegate;
 
-        public RedirectCallHandler(Action<IRedirectCall<TTarget>> redirectDelegate)
+        public RedirectCallHandler(Func<IRedirectCall<TTarget>, object?> redirectDelegate)
         {
             _redirectDelegate = redirectDelegate;
         }
@@ -15,9 +15,55 @@ public RedirectCallHandler(Action<IRedirectCall<TTarget>> redirectDelegate)
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public object? Handle(IRedirectCall<TTarget> call)
         {
-            _redirectDelegate.Invoke(call);
+            return _redirectDelegate.Invoke(call);
+        }
+    }
+    
+    internal class RedirectArgsCallHandler<TTarget> : ICallHandler<TTarget> where TTarget : class
+    {
+        private readonly Func<IRedirectCall<TTarget>, CallArguments, object?> _redirectDelegate;
+
+        public RedirectArgsCallHandler(Func<IRedirectCall<TTarget>, CallArguments, object?> redirectDelegate)
+        {
+            _redirectDelegate = redirectDelegate;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public object? Handle(IRedirectCall<TTarget> call)
+        {
+            return _redirectDelegate.Invoke(call, call.Args);
+        }
+    }
+    
+    internal class RedirectCallHandler : ICallHandler
+    {
+        private readonly Func<IRedirectCall, object?> _redirectDelegate;
+
+        public RedirectCallHandler(Func<IRedirectCall, object?> redirectDelegate)
+        {
+            _redirectDelegate = redirectDelegate;
+        }
 
-            return default;
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public object? Handle(IRedirectCall call)
+        {
+            return _redirectDelegate.Invoke(call);
+        }
+    }
+    
+    internal class RedirectArgsCallHandler : ICallHandler
+    {
+        private readonly Func<IRedirectCall, CallArguments, object?> _redirectDelegate;
+
+        public RedirectArgsCallHandler(Func<IRedirectCall, CallArguments, object?> redirectDelegate)
+        {
+            _redirectDelegate = redirectDelegate;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public object? Handle(IRedirectCall call)
+        {
+            return _redirectDelegate.Invoke(call, call.Args);
         }
     }
 }
\ No newline at end of file
diff --git a/src/DivertR/Internal/ViaBuilder.cs b/src/DivertR/Internal/ViaBuilder.cs
index 2af48245..8ad2b341 100644
--- a/src/DivertR/Internal/ViaBuilder.cs
+++ b/src/DivertR/Internal/ViaBuilder.cs
@@ -20,10 +20,43 @@ public IViaBuilder<TTarget> AddConstraint(ICallConstraint<TTarget> callConstrain
 
             return this;
         }
-        
+
+        public IViaBuilder<TTarget> Redirect(object? instance, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        {
+            var redirect = RedirectBuilder.Build(instance, optionsAction);
+            Via.RedirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IViaBuilder<TTarget> Redirect(Func<object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        {
+            var redirect = RedirectBuilder.Build(redirectDelegate, optionsAction);
+            Via.RedirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IViaBuilder<TTarget> Redirect(Func<IRedirectCall<TTarget>, object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        {
+            var redirect = RedirectBuilder.Build(redirectDelegate, optionsAction);
+            Via.RedirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
+        public IViaBuilder<TTarget> Redirect(Func<IRedirectCall<TTarget>, CallArguments, object?> redirectDelegate, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
+        {
+            var redirect = RedirectBuilder.Build(redirectDelegate, optionsAction);
+            Via.RedirectRepository.InsertRedirect(redirect);
+
+            return this;
+        }
+
         public IViaBuilder<TTarget> Retarget(TTarget target, Action<IRedirectOptionsBuilder<TTarget>>? optionsAction = null)
         {
-            var redirect = RedirectBuilder.Build(target, optionsAction);
+            ICallHandler<TTarget> callHandler = new TargetCallHandler<TTarget>(target);
+            var redirect = RedirectBuilder.Build(callHandler, optionsAction);
             Via.RedirectRepository.InsertRedirect(redirect);
 
             return this;
diff --git a/test/DivertR.UnitTests/DummyRootTests.cs b/test/DivertR.UnitTests/DummyRootTests.cs
index 23348ab9..97dee939 100644
--- a/test/DivertR.UnitTests/DummyRootTests.cs
+++ b/test/DivertR.UnitTests/DummyRootTests.cs
@@ -3,6 +3,7 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Threading.Tasks;
+using DivertR.Dummy;
 using DivertR.UnitTests.Model;
 using Shouldly;
 using Xunit;
@@ -11,7 +12,14 @@ namespace DivertR.UnitTests
 {
     public class DummyRootTests
     {
-        private readonly IVia<IFoo> _via = new Via<IFoo>();
+        private readonly IVia<IFoo> _via;
+        private readonly DummyFactory _dummyFactory = new();
+
+        public DummyRootTests()
+        {
+            var settings = new DiverterSettings(dummyFactory: _dummyFactory);
+            _via = new Via<IFoo>(settings);
+        }
 
         [Fact]
         public void GivenDummyRootProxy_WhenStringPropertyGetterCalled_ShouldReturnNull()
@@ -513,20 +521,18 @@ public void GivenDummyRootProxy_WhenCallHasTuple8Return_ShouldReturnTupleWithDef
             result.Item7.ShouldBe(Task.CompletedTask);
             result.Rest.Item1.ShouldBe(Task.CompletedTask);
         }
-        
+
         [Fact]
-        public void GivenDummyRedirectRepositoryWithReturnTypeRedirect_WhenProxyMethodReturnTypeMatches_ShouldRedirect()
+        public void GivenDummyReturnTypeDelegateRedirect_WhenProxyMethodReturnTypeMatches_ShouldRedirect()
         {
             // ARRANGE
-            var redirect = RedirectBuilder
+            _dummyFactory
                 .To(() => Is<string>.Return)
-                .Build(call => $"{call.Args.FirstOrDefault()} redirected".Trim());
+                .Redirect(() => "redirected")
+                .Redirect(call => $"{call.CallNext()} call {call.Args.LastOrDefault()}".Trim())
+                .Redirect((call, args) => $"{call.CallNext()} args {args.LastOrDefault()}".Trim());
             
-            var diverterSettings = new DiverterSettings();
-            diverterSettings.DummyRedirectRepository.InsertRedirect(redirect);
-           
-            var via = new Via<IFoo>(diverterSettings);
-            var proxy = via.Proxy();
+            var proxy = _via.Proxy();
 
             // ACT
             var result = proxy.EchoGeneric("hello");
@@ -534,9 +540,78 @@ public void GivenDummyRedirectRepositoryWithReturnTypeRedirect_WhenProxyMethodRe
             var objectReturn = proxy.EchoGeneric<object>("hello");
 
             // ASSERT
-            result.ShouldBe("hello redirected");
-            name.ShouldBe("redirected");
+            result.ShouldBe("redirected call hello args hello");
+            name.ShouldBe("redirected call args");
             objectReturn.ShouldBeNull();
         }
+        
+        [Fact]
+        public void GivenDummyReturnTypeInstanceRedirect_WhenProxyMethodReturnSubTypeMatches_ShouldNotRedirect()
+        {
+            // ARRANGE
+            _dummyFactory
+                .To(() => Is<object>.Return)
+                .Redirect("redirected");
+            
+            var proxy = _via.Proxy();
+
+            // ACT
+            var result = proxy.EchoGeneric("hello");
+            var name = proxy.Name;
+            var objectReturn = proxy.EchoGeneric<object>("hello");
+
+            // ASSERT
+            result.ShouldBeNull();
+            name.ShouldBeNull();
+            objectReturn.ShouldBe("redirected");
+        }
+        
+        [Fact]
+        public void GivenDummyConstraintRedirect_WhenConstraintMatches_ShouldRedirect()
+        {
+            // ARRANGE
+            _dummyFactory
+                .To(new CallConstraint(call => call.Method.ReturnType.IsAssignableFrom(typeof(string))))
+                .Redirect(() => "redirected")
+                .Redirect(call => $"{call.CallNext()} call {call.Args.LastOrDefault()}".Trim())
+                .Redirect((call, args) => $"{call.CallNext()} args {args.LastOrDefault()}".Trim());
+            
+            var proxy = _via.Proxy();
+
+            // ACT
+            var result = proxy.EchoGeneric("hello");
+            var name = proxy.Name;
+            var objectReturn = proxy.EchoGeneric<object>("hello");
+            var intReturn = proxy.EchoGeneric(1);
+
+            // ASSERT
+            result.ShouldBe("redirected call hello args hello");
+            name.ShouldBe("redirected call args");
+            objectReturn.ShouldBe("redirected call hello args hello");
+            intReturn.ShouldBe(0);
+        }
+        
+        [Fact]
+        public void GivenDummyConstraintInstanceRedirect_WhenConstraintMatches_ShouldRedirect()
+        {
+            // ARRANGE
+            _dummyFactory
+                .To(new CallConstraint(call => call.Method.ReturnType.IsAssignableFrom(typeof(string))))
+                .Redirect("redirected");
+
+            var proxy = _via.Proxy();
+
+            // ACT
+            var result = proxy.EchoGeneric("hello");
+            var name = proxy.Name;
+            var objectReturn = proxy.EchoGeneric<object>("hello");
+            var intReturn = proxy.EchoGeneric(1);
+
+            // ASSERT
+            result.ShouldBe("redirected");
+            name.ShouldBe("redirected");
+            objectReturn.ShouldBe("redirected");
+            intReturn.ShouldBe(0);
+        }
     }
 }
\ No newline at end of file
diff --git a/test/DivertR.UnitTests/ViaRedirectTests.cs b/test/DivertR.UnitTests/ViaRedirectTests.cs
index 17cfab04..a464efe5 100644
--- a/test/DivertR.UnitTests/ViaRedirectTests.cs
+++ b/test/DivertR.UnitTests/ViaRedirectTests.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Linq;
 using DivertR.UnitTests.Model;
 using Moq;
 using Shouldly;
@@ -993,5 +994,53 @@ public void GivenMoqIsArgumentSyntax_ShouldThrowException()
             // ASSERT
             testAction.ShouldThrow<ArgumentException>();
         }
+        
+        [Fact]
+        public void GivenConstraintRedirect_WhenConstraintMatches_ShouldRedirect()
+        {
+            // ARRANGE
+            _via
+                .To(new CallConstraint<IFoo>(call => call.Method.ReturnType.IsAssignableFrom(typeof(string))))
+                .Redirect(() => "redirected")
+                .Redirect(call => $"{call.CallNext()} call {call.Args.LastOrDefault()}".Trim())
+                .Redirect((call, args) => $"{call.CallNext()} args {args.LastOrDefault()}".Trim());
+            
+            var proxy = _via.Proxy();
+
+            // ACT
+            var result = proxy.EchoGeneric("hello");
+            var name = proxy.Name;
+            var objectReturn = proxy.EchoGeneric<object>("hello");
+            var intReturn = proxy.EchoGeneric(1);
+
+            // ASSERT
+            result.ShouldBe("redirected call hello args hello");
+            name.ShouldBe("redirected call args");
+            objectReturn.ShouldBe("redirected call hello args hello");
+            intReturn.ShouldBe(0);
+        }
+        
+        [Fact]
+        public void GivenConstraintInstanceRedirect_WhenConstraintMatches_ShouldRedirect()
+        {
+            // ARRANGE
+            _via
+                .To(new CallConstraint<IFoo>(call => call.Method.ReturnType.IsAssignableFrom(typeof(string))))
+                .Redirect("redirected");
+
+            var proxy = _via.Proxy();
+
+            // ACT
+            var result = proxy.EchoGeneric("hello");
+            var name = proxy.Name;
+            var objectReturn = proxy.EchoGeneric<object>("hello");
+            var intReturn = proxy.EchoGeneric(1);
+
+            // ASSERT
+            result.ShouldBe("redirected");
+            name.ShouldBe("redirected");
+            objectReturn.ShouldBe("redirected");
+            intReturn.ShouldBe(0);
+        }
     }
 }
\ No newline at end of file