Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Enhancements:
Bugfixes:
- `InvalidProgramException` when proxying `MemoryStream` with .NET 7 (@stakx, #651)
- `invocation.MethodInvocationTarget` throws `ArgumentNullException` for default interface method (@stakx, #684)
- `DynamicProxyException` ("duplicate element") when type to proxy contains members whose names differ only in case (@stakx, #691)

Deprecations:
- .NET Core 2.1, .NET Core 3.1, .NET 6, and mono tests
Expand Down
103 changes: 103 additions & 0 deletions src/Castle.Core.Tests/DynamicProxy.Tests/CaseSensitivityTestCase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright 2004-2025 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.DynamicProxy.Tests
{
using System;

using Castle.DynamicProxy.Tests.Interceptors;

using NUnit.Framework;

[TestFixture]
public class CaseSensitivityTestCase : BasePEVerifyTestCase
{
[TestCase(typeof(IDifferentlyCasedEvents))]
[TestCase(typeof(IDifferentlyCasedMethods))]
[TestCase(typeof(IDifferentlyCasedProperties))]
public void Can_proxy_type_with_differently_cased_members(Type interfaceTypeToProxy)
{
_ = generator.CreateInterfaceProxyWithoutTarget(interfaceTypeToProxy);
}

[Test]
public void Can_distinguish_differently_cased_events_during_interception()
{
var interceptor = new KeepDataInterceptor();
var proxy = generator.CreateInterfaceProxyWithoutTarget<IDifferentlyCasedEvents>(interceptor);

proxy.Abc += delegate { };
Assert.AreEqual("add_Abc", interceptor.Invocation.Method.Name);

proxy.aBc += delegate { };
Assert.AreEqual("add_aBc", interceptor.Invocation.Method.Name);

proxy.abC += delegate { };
Assert.AreEqual("add_abC", interceptor.Invocation.Method.Name);
}

[Test]
public void Can_distinguish_differently_cased_methods_during_interception()
{
var interceptor = new KeepDataInterceptor();
var proxy = generator.CreateInterfaceProxyWithoutTarget<IDifferentlyCasedMethods>(interceptor);

proxy.Abc();
Assert.AreEqual("Abc", interceptor.Invocation.Method.Name);

proxy.aBc();
Assert.AreEqual("aBc", interceptor.Invocation.Method.Name);

proxy.abC();
Assert.AreEqual("abC", interceptor.Invocation.Method.Name);
}

[Test]
public void Can_distinguish_differently_cased_properties_during_interception()
{
var interceptor = new KeepDataInterceptor();
var proxy = generator.CreateInterfaceProxyWithoutTarget<IDifferentlyCasedProperties>(interceptor);

_ = proxy.Abc;
Assert.AreEqual("get_Abc", interceptor.Invocation.Method.Name);

_ = proxy.aBc;
Assert.AreEqual("get_aBc", interceptor.Invocation.Method.Name);

_ = proxy.abC;
Assert.AreEqual("get_abC", interceptor.Invocation.Method.Name);
}

public interface IDifferentlyCasedEvents
{
event EventHandler Abc;
event EventHandler aBc;
event EventHandler abC;
}

public interface IDifferentlyCasedMethods
{
void Abc();
void aBc();
void abC();
}

public interface IDifferentlyCasedProperties
{
object Abc { get; }
object aBc { get; }
object abC { get; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
private readonly List<EventEmitter> events;

private readonly IDictionary<string, FieldReference> fields =
new Dictionary<string, FieldReference>(StringComparer.OrdinalIgnoreCase);
new Dictionary<string, FieldReference>(StringComparer.Ordinal);

private readonly List<MethodEmitter> methods;

Expand All @@ -44,7 +44,7 @@
private GenericTypeParameterBuilder[] genericTypeParams;

internal const TypeAttributes DefaultTypeAttributes =
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable;

Check warning on line 47 in src/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs

View workflow job for this annotation

GitHub Actions / Build and test (windows-latest)

'TypeAttributes.Serializable' is obsolete: 'Formatter-based serialization is obsolete and should not be used.' (https://aka.ms/dotnet-warnings/SYSLIB0050)

Check warning on line 47 in src/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest)

'TypeAttributes.Serializable' is obsolete: 'Formatter-based serialization is obsolete and should not be used.' (https://aka.ms/dotnet-warnings/SYSLIB0050)

Check warning on line 47 in src/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs

View workflow job for this annotation

GitHub Actions / Build and test (macos-latest)

'TypeAttributes.Serializable' is obsolete: 'Formatter-based serialization is obsolete and should not be used.' (https://aka.ms/dotnet-warnings/SYSLIB0050)

public ClassEmitter(TypeBuilder typeBuilder)
{
Expand Down Expand Up @@ -195,7 +195,7 @@

if (!serializable)
{
atts |= FieldAttributes.NotSerialized;

Check warning on line 198 in src/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs

View workflow job for this annotation

GitHub Actions / Build and test (windows-latest)

'FieldAttributes.NotSerialized' is obsolete: 'Formatter-based serialization is obsolete and should not be used.' (https://aka.ms/dotnet-warnings/SYSLIB0050)

Check warning on line 198 in src/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest)

'FieldAttributes.NotSerialized' is obsolete: 'Formatter-based serialization is obsolete and should not be used.' (https://aka.ms/dotnet-warnings/SYSLIB0050)

Check warning on line 198 in src/Castle.Core/DynamicProxy/Generators/Emitters/ClassEmitter.cs

View workflow job for this annotation

GitHub Actions / Build and test (macos-latest)

'FieldAttributes.NotSerialized' is obsolete: 'Formatter-based serialization is obsolete and should not be used.' (https://aka.ms/dotnet-warnings/SYSLIB0050)
}

return CreateField(name, fieldType, atts);
Expand Down
4 changes: 2 additions & 2 deletions src/Castle.Core/DynamicProxy/Generators/MetaEvent.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2004-2021 Castle Project - http://www.castleproject.org/
// Copyright 2004-2025 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -128,7 +128,7 @@ public bool Equals(MetaEvent other)
return true;
}

if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name))
if (!StringComparer.Ordinal.Equals(Name, other.Name))
{
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Castle.Core/DynamicProxy/Generators/MetaMethod.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2004-2021 Castle Project - http://www.castleproject.org/
// Copyright 2004-2025 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -61,7 +61,7 @@ public bool Equals(MetaMethod other)
return true;
}

if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name))
if (!StringComparer.Ordinal.Equals(Name, other.Name))
{
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions src/Castle.Core/DynamicProxy/Generators/MetaProperty.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2004-2021 Castle Project - http://www.castleproject.org/
// Copyright 2004-2025 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -159,7 +159,7 @@ public bool Equals(MetaProperty other)
return true;
}

if (!StringComparer.OrdinalIgnoreCase.Equals(Name, other.Name))
if (!StringComparer.Ordinal.Equals(Name, other.Name))
{
return false;
}
Expand Down
8 changes: 4 additions & 4 deletions src/Castle.Core/DynamicProxy/Internal/TypeUtil.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2004-2021 Castle Project - http://www.castleproject.org/
// Copyright 2004-2025 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -139,7 +139,7 @@
internal static bool HasAnyOverridableDefaultImplementations(this Type interfaceType)
{
Debug.Assert(interfaceType != null);
Debug.Assert(interfaceType.IsInterface);

Check warning on line 142 in src/Castle.Core/DynamicProxy/Internal/TypeUtil.cs

View workflow job for this annotation

GitHub Actions / Build and test (windows-latest)

Dereference of a possibly null reference.

Check warning on line 142 in src/Castle.Core/DynamicProxy/Internal/TypeUtil.cs

View workflow job for this annotation

GitHub Actions / Build and test (windows-latest)

Dereference of a possibly null reference.

Check warning on line 142 in src/Castle.Core/DynamicProxy/Internal/TypeUtil.cs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 142 in src/Castle.Core/DynamicProxy/Internal/TypeUtil.cs

View workflow job for this annotation

GitHub Actions / Build and test (ubuntu-latest)

Dereference of a possibly null reference.

Check warning on line 142 in src/Castle.Core/DynamicProxy/Internal/TypeUtil.cs

View workflow job for this annotation

GitHub Actions / Build and test (macos-latest)

Dereference of a possibly null reference.

Check warning on line 142 in src/Castle.Core/DynamicProxy/Internal/TypeUtil.cs

View workflow job for this annotation

GitHub Actions / Build and test (macos-latest)

Dereference of a possibly null reference.

var cache = hasAnyOverridableDefaultImplementationsCache;
lock (cache)
Expand Down Expand Up @@ -195,12 +195,12 @@

internal static bool IsGetType(this MethodInfo methodInfo)
{
return methodInfo.DeclaringType == typeof(object) && string.Equals("GetType", methodInfo.Name, StringComparison.OrdinalIgnoreCase);
return methodInfo.DeclaringType == typeof(object) && string.Equals("GetType", methodInfo.Name, StringComparison.Ordinal);
}

internal static bool IsMemberwiseClone(this MethodInfo methodInfo)
{
return methodInfo.DeclaringType == typeof(object) && string.Equals("MemberwiseClone", methodInfo.Name, StringComparison.OrdinalIgnoreCase);
return methodInfo.DeclaringType == typeof(object) && string.Equals("MemberwiseClone", methodInfo.Name, StringComparison.Ordinal);
}

internal static void SetStaticField(this Type type, string fieldName, BindingFlags additionalFlags, object? value)
Expand Down Expand Up @@ -252,7 +252,7 @@
{
var sortedMembers = new MemberInfo[members.Length];
Array.Copy(members, sortedMembers, members.Length);
Array.Sort(sortedMembers, (l, r) => string.Compare(l.Name, r.Name, StringComparison.OrdinalIgnoreCase));
Array.Sort(sortedMembers, (l, r) => string.Compare(l.Name, r.Name, StringComparison.Ordinal));
return sortedMembers;
}

Expand Down
Loading