Skip to content

Commit 57e666d

Browse files
authored
Merge pull request castleproject#658 from stakx/bug/generic-enum-constraint
Fix `ArgumentException` caused by `Enum` constraint on method `out` parameter
2 parents 2537a23 + 1bc7f18 commit 57e666d

File tree

4 files changed

+50
-18
lines changed

4 files changed

+50
-18
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Enhancements:
88

99
Bugfixes:
1010
- `ArgumentException`: "Could not find method overriding method" with overridden class method having generic by-ref parameter (@stakx, #657)
11+
- `ArgumentException`: "Cannot create an instance of `TEnum` because `Type.ContainsGenericParameters` is true" caused by `Enum` constraint on method `out` parameter (@stakx, #658)
1112

1213
## 5.1.1 (2022-12-30)
1314

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2004-2023 Castle Project - http://www.castleproject.org/
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace Castle.DynamicProxy.Tests.GenInterfaces
16+
{
17+
using System;
18+
19+
public interface IHaveGenericMethodWithEnumConstraint
20+
{
21+
void Method<TEnum>(out TEnum result) where TEnum : Enum;
22+
}
23+
}

src/Castle.Core.Tests/DynamicProxy.Tests/GenericConstraintsTestCase.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,12 @@ public void Generic_type_generic_method_with_struct_base_Method_base_Type_constr
3333
CreateProxyFor<IConstraint_Method1IsTypeStructAndMethod2<object>>();
3434
}
3535

36+
[Test]
37+
public void Non_generic_type_generic_method_with_by_ref_parameter_type_constrained_to_Enum()
38+
{
39+
CreateProxyFor<IHaveGenericMethodWithEnumConstraint>();
40+
}
41+
3642

3743
private T CreateProxyFor<T>(params IInterceptor[] interceptors) where T : class
3844
{

src/Castle.Core/DynamicProxy/Generators/Emitters/OpCodeUtil.cs

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,6 @@ internal abstract class OpCodeUtil
2727
/// </summary>
2828
public static void EmitLoadIndirectOpCodeForType(ILGenerator gen, Type type)
2929
{
30-
if (type.IsEnum)
31-
{
32-
EmitLoadIndirectOpCodeForType(gen, GetUnderlyingTypeOfEnum(type));
33-
return;
34-
}
35-
3630
if (type.IsByRef)
3731
{
3832
throw new NotSupportedException("Cannot load ByRef values");
@@ -48,13 +42,20 @@ public static void EmitLoadIndirectOpCodeForType(ILGenerator gen, Type type)
4842

4943
gen.Emit(opCode);
5044
}
51-
else if (type.IsValueType)
45+
else if (type.IsGenericParameter)
5246
{
5347
gen.Emit(OpCodes.Ldobj, type);
5448
}
55-
else if (type.IsGenericParameter)
49+
else if (type.IsValueType)
5650
{
57-
gen.Emit(OpCodes.Ldobj, type);
51+
if (type.IsEnum)
52+
{
53+
EmitLoadIndirectOpCodeForType(gen, GetUnderlyingTypeOfEnum(type));
54+
}
55+
else
56+
{
57+
gen.Emit(OpCodes.Ldobj, type);
58+
}
5859
}
5960
else
6061
{
@@ -107,12 +108,6 @@ public static void EmitLoadOpCodeForDefaultValueOfType(ILGenerator gen, Type typ
107108
/// </summary>
108109
public static void EmitStoreIndirectOpCodeForType(ILGenerator gen, Type type)
109110
{
110-
if (type.IsEnum)
111-
{
112-
EmitStoreIndirectOpCodeForType(gen, GetUnderlyingTypeOfEnum(type));
113-
return;
114-
}
115-
116111
if (type.IsByRef)
117112
{
118113
throw new NotSupportedException("Cannot store ByRef values");
@@ -128,13 +123,20 @@ public static void EmitStoreIndirectOpCodeForType(ILGenerator gen, Type type)
128123

129124
gen.Emit(opCode);
130125
}
131-
else if (type.IsValueType)
126+
else if (type.IsGenericParameter)
132127
{
133128
gen.Emit(OpCodes.Stobj, type);
134129
}
135-
else if (type.IsGenericParameter)
130+
else if (type.IsValueType)
136131
{
137-
gen.Emit(OpCodes.Stobj, type);
132+
if (type.IsEnum)
133+
{
134+
EmitStoreIndirectOpCodeForType(gen, GetUnderlyingTypeOfEnum(type));
135+
}
136+
else
137+
{
138+
gen.Emit(OpCodes.Stobj, type);
139+
}
138140
}
139141
else
140142
{

0 commit comments

Comments
 (0)