diff --git a/Source/Capture.cs b/Source/Capture.cs
new file mode 100644
index 000000000..ef5340359
--- /dev/null
+++ b/Source/Capture.cs
@@ -0,0 +1,97 @@
+//Copyright (c) 2007. Clarius Consulting, Manas Technology Solutions, InSTEDD
+//http://code.google.com/p/moq/
+//All rights reserved.
+
+//Redistribution and use in source and binary forms,
+//with or without modification, are permitted provided
+//that the following conditions are met:
+
+// * Redistributions of source code must retain the
+// above copyright notice, this list of conditions and
+// the following disclaimer.
+
+// * Redistributions in binary form must reproduce
+// the above copyright notice, this list of conditions
+// and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+
+// * Neither the name of Clarius Consulting, Manas Technology Solutions or InSTEDD nor the
+// names of its contributors may be used to endorse
+// or promote products derived from this software
+// without specific prior written permission.
+
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+//CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+//MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+//WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+//OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+//SUCH DAMAGE.
+
+//[This is the BSD license, see
+// http://www.opensource.org/licenses/bsd-license.php]
+
+using System;
+using System.Collections.Generic;
+using System.Linq.Expressions;
+
+namespace Moq
+{
+ ///
+ /// Allows to create parameter captures in setup expressions.
+ ///
+ public static class Capture
+ {
+ ///
+ /// Creates a parameter capture that will store items in a collection.
+ ///
+ /// The captured object item
+ /// The collection that will store captured parameter values
+ ///
+ /// Arrange code:
+ ///
+ /// var parameters = new List{string}();
+ /// mock.Setup(x => x.DoSomething(Capture.In(parameters)));
+ ///
+ /// Assert code:
+ ///
+ /// Assert.Equal("Hello!", parameters.Single());
+ ///
+ ///
+ public static T In(IList collection)
+ {
+ var capture = new MockCapture(collection);
+ return capture.CaptureAny();
+ }
+
+ ///
+ /// Creates a parameter capture that will store specific items in a collection.
+ ///
+ /// The captured object item
+ /// The collection that will store captured parameter values
+ /// A predicate used to filter captured parameters
+ ///
+ /// Arrange code:
+ ///
+ /// var parameters = new List{string}();
+ /// mock.Setup(x => x.DoSomething(Capture.In(parameters, p => p.StartsWith("W"))));
+ ///
+ /// Assert code:
+ ///
+ /// Assert.Equal("Hello!", parameters.Single());
+ ///
+ ///
+ public static T In(IList collection, Expression> match)
+ {
+ var capture = new MockCapture(collection);
+ return capture.Capture(match);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/MockCapture.cs b/Source/MockCapture.cs
new file mode 100644
index 000000000..90049b4c3
--- /dev/null
+++ b/Source/MockCapture.cs
@@ -0,0 +1,148 @@
+//Copyright (c) 2007. Clarius Consulting, Manas Technology Solutions, InSTEDD
+//http://code.google.com/p/moq/
+//All rights reserved.
+
+//Redistribution and use in source and binary forms,
+//with or without modification, are permitted provided
+//that the following conditions are met:
+
+// * Redistributions of source code must retain the
+// above copyright notice, this list of conditions and
+// the following disclaimer.
+
+// * Redistributions in binary form must reproduce
+// the above copyright notice, this list of conditions
+// and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+
+// * Neither the name of Clarius Consulting, Manas Technology Solutions or InSTEDD nor the
+// names of its contributors may be used to endorse
+// or promote products derived from this software
+// without specific prior written permission.
+
+//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+//CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+//INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+//MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+//SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+//BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+//INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+//WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+//OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+//SUCH DAMAGE.
+
+//[This is the BSD license, see
+// http://www.opensource.org/licenses/bsd-license.php]
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace Moq
+{
+ ///
+ /// Captures mock parameters.
+ ///
+ ///
+ /// Arrange code:
+ ///
+ /// var capture = new MockCapture{string}();
+ /// mock.Setup(x => x.DoSomething(capture.CaptureAny()));
+ ///
+ /// Assert code:
+ ///
+ /// Assert.Equal("Hello!", capture.Last);
+ ///
+ ///
+ public class MockCapture
+ {
+ private static readonly Func identity = _ => _;
+ private readonly IList capturedValues = new List();
+ private readonly Func captureCallback;
+
+ ///
+ /// Initializes an instance of the capture.
+ ///
+ public MockCapture()
+ : this(identity)
+ {
+ }
+
+ ///
+ /// Initializes an instance of the capture.
+ ///
+ /// An action to run on captured value
+ public MockCapture(Action captureCallback)
+ : this(CreateCaptureCallback(captureCallback))
+ {
+ }
+
+ ///
+ /// Initializes an instance of the capture.
+ ///
+ /// A transform function to apply to captured values
+ public MockCapture(Func captureCallback)
+ {
+ this.captureCallback = captureCallback;
+ this.capturedValues = new List();
+ this.Values = new ReadOnlyCollection(this.capturedValues);
+ }
+
+ internal MockCapture(IList capturedValues)
+ {
+ this.captureCallback = identity;
+ this.capturedValues = capturedValues;
+ this.Values = new ReadOnlyCollection(this.capturedValues);
+ }
+
+ ///
+ /// Gets all the captured values.
+ ///
+ public IReadOnlyList Values { get; private set; }
+
+ ///
+ /// Gets the last captured value.
+ ///
+ public T LastValue { get { return this.Values.Last(); } }
+
+ ///
+ /// Gets the parameter to use in the setup expression.
+ ///
+ public T CaptureAny()
+ {
+ return Match.Create(value => this.EvaluateParameter(value), () => It.IsAny());
+ }
+
+ ///
+ /// Gets the parameter to use in the setup expression.
+ ///
+ public T Capture(Expression> match)
+ {
+ var matchDelegate = match.Compile();
+ return Match.Create(value => matchDelegate.Invoke(value) && this.EvaluateParameter(value), () => It.Is(match));
+ }
+
+ private bool EvaluateParameter(T item)
+ {
+ var capturedValue = this.captureCallback.Invoke(item);
+ this.capturedValues.Add(capturedValue);
+
+ return true;
+ }
+
+ private static Func CreateCaptureCallback(Action action)
+ {
+ return x =>
+ {
+ action.Invoke(x);
+ return x;
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/Moq.csproj b/Source/Moq.csproj
index 4e72af310..118e885db 100644
--- a/Source/Moq.csproj
+++ b/Source/Moq.csproj
@@ -42,6 +42,7 @@
+
@@ -64,6 +65,7 @@
True
IReturns.tt
+
diff --git a/UnitTests/CaptureFixture.cs b/UnitTests/CaptureFixture.cs
new file mode 100644
index 000000000..942aa1515
--- /dev/null
+++ b/UnitTests/CaptureFixture.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using Xunit;
+
+namespace Moq.Tests
+{
+ public class CaptureFixture
+ {
+ [Fact]
+ public void CanCaptureAnyParameterInCollection()
+ {
+ var items = new List();
+ var mock = new Mock();
+ mock.Setup(x => x.DoSomething(Capture.In(items)));
+
+ mock.Object.DoSomething("Hello!");
+
+ var expectedValues = new List { "Hello!" };
+ Assert.Equal(expectedValues, items);
+ }
+
+ [Fact]
+ public void CanCaptureSpecificParameterInCollection()
+ {
+ var items = new List();
+ var mock = new Mock();
+ mock.Setup(x => x.DoSomething(Capture.In(items, p => p.StartsWith("W"))));
+
+ mock.Object.DoSomething("Hello!");
+ mock.Object.DoSomething("World!");
+
+ var expectedValues = new List { "World!" };
+ Assert.Equal(expectedValues, items);
+ }
+
+ public interface IFoo
+ {
+ void DoSomething(string s);
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/MockCaptureFixture.cs b/UnitTests/MockCaptureFixture.cs
new file mode 100644
index 000000000..73fee6223
--- /dev/null
+++ b/UnitTests/MockCaptureFixture.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Generic;
+using Xunit;
+
+namespace Moq.Tests
+{
+ public class MockCaptureFixture
+ {
+ [Fact]
+ public void CanCaptureParameter()
+ {
+ var capture = new MockCapture();
+ var mock = new Mock();
+ mock.Setup(x => x.DoSomething(capture.CaptureAny()));
+
+ mock.Object.DoSomething("Hello!");
+
+ var expectedValues = new List { "Hello!" }.AsReadOnly();
+ Assert.Equal(expectedValues, capture.Values);
+ }
+
+ [Fact]
+ public void CanCaptureMultipleParameters()
+ {
+ var capture = new MockCapture();
+ var mock = new Mock();
+ mock.Setup(x => x.DoSomething(capture.CaptureAny()));
+
+ mock.Object.DoSomething("Hello!");
+ mock.Object.DoSomething("World!");
+
+ var expectedValues = new List { "Hello!", "World!" }.AsReadOnly();
+ Assert.Equal(expectedValues, capture.Values);
+ }
+
+ [Fact]
+ public void CanCaptureSpecificParameter()
+ {
+ var capture = new MockCapture();
+ var mock = new Mock();
+ mock.Setup(x => x.DoSomething(capture.Capture(p => p.StartsWith("W"))));
+
+ mock.Object.DoSomething("Hello!");
+ mock.Object.DoSomething("World!");
+
+ var expectedValues = new List { "World!" }.AsReadOnly();
+ Assert.Equal(expectedValues, capture.Values);
+ }
+
+ [Fact]
+ public void CanCaptureLastParameter()
+ {
+ var capture = new MockCapture();
+ var mock = new Mock();
+ mock.Setup(x => x.DoSomething(capture.CaptureAny()));
+
+ mock.Object.DoSomething("Hello!");
+ mock.Object.DoSomething("World!");
+
+ Assert.Equal("World!", capture.LastValue);
+ }
+
+ [Fact]
+ public void CanRunActionCallback()
+ {
+ var capture = new MockCapture(x => x.Value = 42);
+ var mock = new Mock();
+ mock.Setup(x => x.DoSomething(capture.CaptureAny()));
+
+ var param = new FooParam(0);
+ mock.Object.DoSomething(param);
+
+ Assert.Equal(42, param.Value);
+ Assert.Equal(42, capture.LastValue.Value);
+ }
+
+ [Fact]
+ public void CanRunFuncCallback()
+ {
+ var capture = new MockCapture(x => new FooParam(x.Value));
+ var mock = new Mock();
+ mock.Setup(x => x.DoSomething(capture.CaptureAny()));
+
+ var param = new FooParam(41);
+ mock.Object.DoSomething(param);
+ param.Value = 42;
+ mock.Object.DoSomething(param);
+ param.Value = 0;
+
+ var expectedValues = new List { new FooParam(41), new FooParam(42) }.AsReadOnly();
+ Assert.Equal(expectedValues, capture.Values);
+ }
+
+ public interface IFoo
+ {
+ void DoSomething(string item);
+ void DoSomething(FooParam item);
+ }
+
+ public class FooParam : IEquatable
+ {
+ public FooParam(int value)
+ {
+ Value = value;
+ }
+
+ public int Value { get; set; }
+
+ public bool Equals(FooParam other)
+ {
+ return other != null && Value == other.Value;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as FooParam);
+ }
+
+ public override int GetHashCode()
+ {
+ return Value;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/UnitTests/Moq.Tests.csproj b/UnitTests/Moq.Tests.csproj
index 4356c4210..4aa256781 100644
--- a/UnitTests/Moq.Tests.csproj
+++ b/UnitTests/Moq.Tests.csproj
@@ -55,9 +55,11 @@
+
+