Skip to content

Commit

Permalink
Avoid name collisions for properties & events, too
Browse files Browse the repository at this point in the history
  • Loading branch information
stakx committed Jul 5, 2017
1 parent 55192ae commit 5047f76
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 35 deletions.
72 changes: 65 additions & 7 deletions src/Castle.Core.Tests/BasicInterfaceProxyTestCase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public void Should_implement_explicitly_duplicate_interface_members()
}

[Test]
public void Should_choose_noncolliding_member_names_when_implementing_same_generic_interface_several_times()
public void Should_choose_noncolliding_method_names_when_implementing_same_generic_interface_several_times()
{
var boolInterfaceType = typeof(IGenericWithNonGenericMethod<bool>);
var intInterfaceType = typeof(IGenericWithNonGenericMethod<int>);
Expand All @@ -231,13 +231,71 @@ public void Should_choose_noncolliding_member_names_when_implementing_same_gener
var type = proxy.GetType().GetTypeInfo();

var boolMethod = type.GetRuntimeInterfaceMap(boolInterfaceType).TargetMethods[0];
Assert.AreEqual("DoSomething", boolMethod.Name);
Assert.AreEqual("SomeMethod", boolMethod.Name);

var intMethod = type.GetRuntimeInterfaceMap(intInterfaceType).TargetMethods[0];
Assert.AreEqual("IGenericWithNonGenericMethod`1[Int32].DoSomething", intMethod.Name);
Assert.AreEqual("IGenericWithNonGenericMethod`1[Int32].SomeMethod", intMethod.Name);

var nestedGenericBoolMethod = type.GetRuntimeInterfaceMap(nestedGenericBoolInterfaceType).TargetMethods[0];
Assert.AreEqual("IGenericWithNonGenericMethod`1[IGenericWithNonGenericMethod`1[Boolean]].DoSomething", nestedGenericBoolMethod.Name);
Assert.AreEqual("IGenericWithNonGenericMethod`1[IGenericWithNonGenericMethod`1[Boolean]].SomeMethod", nestedGenericBoolMethod.Name);
}

[Test]
public void Should_choose_noncolliding_property_accessor_names_when_implementing_same_generic_interface_several_times()
{
var boolInterfaceType = typeof(IGenericWithProperty<bool>);
var intInterfaceType = typeof(IGenericWithProperty<int>);
var nestedGenericBoolInterfaceType = typeof(IGenericWithProperty<IGenericWithProperty<bool>>);

var proxy = generator.CreateInterfaceProxyWithoutTarget(
boolInterfaceType,
new[] { intInterfaceType, nestedGenericBoolInterfaceType });

var type = proxy.GetType().GetTypeInfo();

var boolGetter = type.GetRuntimeInterfaceMap(boolInterfaceType).TargetMethods[0];
var boolSetter = type.GetRuntimeInterfaceMap(boolInterfaceType).TargetMethods[1];
Assert.AreEqual("get_SomeProperty", boolGetter.Name);
Assert.AreEqual("set_SomeProperty", boolSetter.Name);

var intGetter = type.GetRuntimeInterfaceMap(intInterfaceType).TargetMethods[0];
var intSetter = type.GetRuntimeInterfaceMap(intInterfaceType).TargetMethods[1];
Assert.AreEqual("IGenericWithProperty`1[Int32].get_SomeProperty", intGetter.Name);
Assert.AreEqual("IGenericWithProperty`1[Int32].set_SomeProperty", intSetter.Name);

var nestedGenericBoolGetter = type.GetRuntimeInterfaceMap(nestedGenericBoolInterfaceType).TargetMethods[0];
var nestedGenericBoolSetter = type.GetRuntimeInterfaceMap(nestedGenericBoolInterfaceType).TargetMethods[1];
Assert.AreEqual("IGenericWithProperty`1[IGenericWithProperty`1[Boolean]].get_SomeProperty", nestedGenericBoolGetter.Name);
Assert.AreEqual("IGenericWithProperty`1[IGenericWithProperty`1[Boolean]].set_SomeProperty", nestedGenericBoolSetter.Name);
}

[Test]
public void Should_choose_noncolliding_event_accessor_names_when_implementing_same_generic_interface_several_times()
{
var boolInterfaceType = typeof(IGenericWithEvent<bool>);
var intInterfaceType = typeof(IGenericWithEvent<int>);
var nestedGenericBoolInterfaceType = typeof(IGenericWithEvent<IGenericWithEvent<bool>>);

var proxy = generator.CreateInterfaceProxyWithoutTarget(
boolInterfaceType,
new[] { intInterfaceType, nestedGenericBoolInterfaceType });

var type = proxy.GetType().GetTypeInfo();

var boolAdder = type.GetRuntimeInterfaceMap(boolInterfaceType).TargetMethods[0];
var boolRemover = type.GetRuntimeInterfaceMap(boolInterfaceType).TargetMethods[1];
Assert.AreEqual("add_SomeEvent", boolAdder.Name);
Assert.AreEqual("remove_SomeEvent", boolRemover.Name);

var intAdder = type.GetRuntimeInterfaceMap(intInterfaceType).TargetMethods[0];
var intRemover = type.GetRuntimeInterfaceMap(intInterfaceType).TargetMethods[1];
Assert.AreEqual("IGenericWithEvent`1[Int32].add_SomeEvent", intAdder.Name);
Assert.AreEqual("IGenericWithEvent`1[Int32].remove_SomeEvent", intRemover.Name);

var nestedGenericBoolAdder = type.GetRuntimeInterfaceMap(nestedGenericBoolInterfaceType).TargetMethods[0];
var nestedGenericBoolRemover = type.GetRuntimeInterfaceMap(nestedGenericBoolInterfaceType).TargetMethods[1];
Assert.AreEqual("IGenericWithEvent`1[IGenericWithEvent`1[Boolean]].add_SomeEvent", nestedGenericBoolAdder.Name);
Assert.AreEqual("IGenericWithEvent`1[IGenericWithEvent`1[Boolean]].remove_SomeEvent", nestedGenericBoolRemover.Name);
}

[Test]
Expand All @@ -254,13 +312,13 @@ public void Should_choose_noncolliding_member_names_when_implementing_same_gener
var type = proxy.GetType().GetTypeInfo();

var boolIntMethod = type.GetRuntimeInterfaceMap(boolIntInterfaceType).TargetMethods[0];
Assert.AreEqual("DoSomething", boolIntMethod.Name);
Assert.AreEqual("SomeMethod", boolIntMethod.Name);

var intBoolMethod = type.GetRuntimeInterfaceMap(intBoolInterfaceType).TargetMethods[0];
Assert.AreEqual("IGenericWithNonGenericMethod`2[Int32,Boolean].DoSomething", intBoolMethod.Name);
Assert.AreEqual("IGenericWithNonGenericMethod`2[Int32,Boolean].SomeMethod", intBoolMethod.Name);

var intNestedGenericBoolMethod = type.GetRuntimeInterfaceMap(intNestedGenericBoolInterfaceType).TargetMethods[0];
Assert.AreEqual("IGenericWithNonGenericMethod`2[Int32,IGenericWithNonGenericMethod`1[Boolean]].DoSomething", intNestedGenericBoolMethod.Name);
Assert.AreEqual("IGenericWithNonGenericMethod`2[Int32,IGenericWithNonGenericMethod`1[Boolean]].SomeMethod", intNestedGenericBoolMethod.Name);
}

private ParameterInfo[] GetMyTestMethodParams(Type type)
Expand Down
23 changes: 23 additions & 0 deletions src/Castle.Core.Tests/Interfaces/IGenericWithEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2004-2010 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.Interfaces
{
using System;

public interface IGenericWithEvent<T>
{
event EventHandler SomeEvent;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ namespace Castle.DynamicProxy.Tests.Interfaces
{
public interface IGenericWithNonGenericMethod<T>
{
void DoSomething();
void SomeMethod();
}

public interface IGenericWithNonGenericMethod<T1, T2>
{
void DoSomething();
void SomeMethod();
}
}
21 changes: 21 additions & 0 deletions src/Castle.Core.Tests/Interfaces/IGenericWithProperty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2004-2010 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.Interfaces
{
public interface IGenericWithProperty<T>
{
object SomeProperty { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/Castle.Core/DynamicProxy/Generators/MetaEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public bool Equals(MetaEvent other)

internal override void SwitchToExplicitImplementation()
{
name = string.Format("{0}.{1}", sourceType.Name, name);
name = MetaTypeElementUtil.CreateNameForExplicitImplementation(sourceType, name);
adder.SwitchToExplicitImplementation();
remover.SwitchToExplicitImplementation();
}
Expand Down
27 changes: 3 additions & 24 deletions src/Castle.Core/DynamicProxy/Generators/MetaMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ namespace Castle.DynamicProxy.Generators
using System;
using System.Diagnostics;
using System.Reflection;
using System.Text;

using Castle.DynamicProxy.Internal;

Expand Down Expand Up @@ -102,29 +101,9 @@ internal override void SwitchToExplicitImplementation()
Attributes |= MethodAttributes.SpecialName;
}

var nameBuilder = new StringBuilder();
AppendTypeNameTo(nameBuilder, Method.DeclaringType);
nameBuilder.Append('.');
nameBuilder.Append(Method.Name);
name = nameBuilder.ToString();
}

private static void AppendTypeNameTo(StringBuilder stringBuilder, Type type)
{
stringBuilder.Append(type.Name);
if (type.GetTypeInfo().IsGenericType)
{
stringBuilder.Append('[');
var genericTypeArguments = type.GetGenericArguments();
for (int i = 0, n = genericTypeArguments.Length; i < n; ++i)
{
if (i > 0)
{
stringBuilder.Append(',');
}
AppendTypeNameTo(stringBuilder, genericTypeArguments[i]);
}
stringBuilder.Append(']');
if (name.Length == Method.Name.Length) // only adjust name once (important for accessor methods)
{
name = MetaTypeElementUtil.CreateNameForExplicitImplementation(sourceType, name);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Castle.Core/DynamicProxy/Generators/MetaProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public bool Equals(MetaProperty other)

internal override void SwitchToExplicitImplementation()
{
name = string.Format("{0}.{1}", sourceType.Name, name);
name = MetaTypeElementUtil.CreateNameForExplicitImplementation(sourceType, name);
if (setter != null)
{
setter.SwitchToExplicitImplementation();
Expand Down
61 changes: 61 additions & 0 deletions src/Castle.Core/DynamicProxy/Generators/MetaTypeElementUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2004-2011 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.Generators
{
using System;
using System.Reflection;
using System.Text;

internal static class MetaTypeElementUtil
{
[ThreadStatic]
private static StringBuilder sharedNameBuilder;

public static string CreateNameForExplicitImplementation(Type sourceType, string name)
{
if (sharedNameBuilder == null)
{
sharedNameBuilder = new StringBuilder();
}

var nameBuilder = sharedNameBuilder;
nameBuilder.Length = 0;
nameBuilder.AppendNameOf(sourceType);
nameBuilder.Append('.');
nameBuilder.Append(name);

return nameBuilder.ToString();
}

private static void AppendNameOf(this StringBuilder nameBuilder, Type type)
{
nameBuilder.Append(type.Name);
if (type.GetTypeInfo().IsGenericType)
{
nameBuilder.Append('[');
var genericTypeArguments = type.GetGenericArguments();
for (int i = 0, n = genericTypeArguments.Length; i < n; ++i)
{
if (i > 0)
{
nameBuilder.Append(',');
}
nameBuilder.AppendNameOf(genericTypeArguments[i]);
}
nameBuilder.Append(']');
}
}
}
}

0 comments on commit 5047f76

Please sign in to comment.