Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't check for IDisposable at runtime for value types #3173

Merged
merged 2 commits into from Aug 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/AutoMapper/Internal/ExpressionFactory.cs
Expand Up @@ -184,8 +184,13 @@ public static Expression Using(Expression disposable, Expression body)
}
else
{
var asDisposable = TypeAs(disposable, typeof(IDisposable));
disposeCall = IfNullElse(asDisposable, Empty(), DisposeExpression.ReplaceParameters(asDisposable));
if (disposable.Type.IsValueType)
{
return body;
}
var disposableVariable = Variable(typeof(IDisposable), "disposableVariable");
var assignDisposable = Assign(disposableVariable, TypeAs(disposable, typeof(IDisposable)));
disposeCall = Block(new[] { disposableVariable }, assignDisposable, IfNullElse(disposableVariable, Empty(), DisposeExpression.ReplaceParameters(disposableVariable)));
}
return TryFinally(body, disposeCall);
}
Expand Down
88 changes: 88 additions & 0 deletions src/UnitTests/CollectionMapping.cs
Expand Up @@ -10,6 +10,94 @@

namespace AutoMapper.UnitTests
{
public class Enumerator_disposable_at_runtime_class : AutoMapperSpecBase
{
class CustomList<T> : List<T>
{
private CustomEnumerator _enumerator;

public new EnumeratorBase GetEnumerator()
{
_enumerator = new CustomEnumerator(base.GetEnumerator(), this);
return _enumerator;
}
public bool Disposed { get; set; }
public class EnumeratorBase
{
public EnumeratorBase(IEnumerator<T> enumerator, CustomList<T> list)
{
Enumerator = enumerator;
List = list;
}
public IEnumerator<T> Enumerator { get; }
public CustomList<T> List { get; }
public T Current => Enumerator.Current;
public void Dispose()
{
Enumerator.Dispose();
List.Disposed = true;
}
public bool MoveNext() => Enumerator.MoveNext();
public void Reset() => Enumerator.Reset();
}
public class CustomEnumerator : EnumeratorBase, IDisposable
{
public CustomEnumerator(IEnumerator<T> enumerator, CustomList<T> list) : base(enumerator, list) { }
}
}

protected override MapperConfiguration Configuration => new MapperConfiguration(_ => { });

[Fact]
public void Should_call_dispose()
{
var source = new CustomList<int>();
Mapper.Map<List<int>>(source);
source.Disposed.ShouldBeTrue();
}
}
public class Enumerator_non_disposable_struct : AutoMapperSpecBase
{
class CustomList<T> : List<T>
{
private CustomEnumerator _enumerator;

public new CustomEnumerator GetEnumerator()
{
_enumerator = new CustomEnumerator(base.GetEnumerator(), this);
return _enumerator;
}
public bool Disposed { get; set; }
public struct CustomEnumerator
{
public CustomEnumerator(IEnumerator<T> enumerator, CustomList<T> list)
{
Enumerator = enumerator;
List = list;
}
public IEnumerator<T> Enumerator { get; }
public CustomList<T> List { get; }
public T Current => Enumerator.Current;
public void Dispose()
{
Enumerator.Dispose();
List.Disposed = true;
}
public bool MoveNext() => Enumerator.MoveNext();
public void Reset() => Enumerator.Reset();
}
}

protected override MapperConfiguration Configuration => new MapperConfiguration(_ => { });

[Fact]
public void Should_not_call_dispose()
{
var source = new CustomList<int>();
Mapper.Map<List<int>>(source);
source.Disposed.ShouldBeFalse();
}
}
public class Enumerator_dispose : AutoMapperSpecBase
{
class CustomList<T> : List<T>
Expand Down