提交 037d1e8f 编写于 作者: A AlekseyTs

Merge pull request #8602 from AlekseyTs/Issue7674

Ensure custom modifiers are copied for types of overriding properties and events even in the case of dynamic/object mismatch.
......@@ -494,7 +494,7 @@ internal static class DynamicTransformsEncoder
internal static ImmutableArray<TypedConstant> Encode(TypeSymbol type, TypeSymbol booleanType, int customModifiersCount, RefKind refKind)
{
var flagsBuilder = ArrayBuilder<bool>.GetInstance();
EncodeInternal(type, customModifiersCount, refKind, flagsBuilder);
EncodeInternal(type, customModifiersCount, refKind, flagsBuilder, addCustomModifierFlags: true);
Debug.Assert(flagsBuilder.Any());
Debug.Assert(flagsBuilder.Contains(true));
......@@ -511,11 +511,18 @@ internal static ImmutableArray<TypedConstant> Encode(TypeSymbol type, TypeSymbol
internal static ImmutableArray<bool> Encode(TypeSymbol type, int customModifiersCount, RefKind refKind)
{
var transformFlagsBuilder = ArrayBuilder<bool>.GetInstance();
EncodeInternal(type, customModifiersCount, refKind, transformFlagsBuilder);
EncodeInternal(type, customModifiersCount, refKind, transformFlagsBuilder, addCustomModifierFlags: true);
return transformFlagsBuilder.ToImmutableAndFree();
}
internal static void EncodeInternal(TypeSymbol type, int customModifiersCount, RefKind refKind, ArrayBuilder<bool> transformFlagsBuilder)
internal static ImmutableArray<bool> EncodeWithoutCustomModifierFlags(TypeSymbol type, RefKind refKind)
{
var transformFlagsBuilder = ArrayBuilder<bool>.GetInstance();
EncodeInternal(type, -1, refKind, transformFlagsBuilder, addCustomModifierFlags: false);
return transformFlagsBuilder.ToImmutableAndFree();
}
private static void EncodeInternal(TypeSymbol type, int customModifiersCount, RefKind refKind, ArrayBuilder<bool> transformFlagsBuilder, bool addCustomModifierFlags)
{
Debug.Assert(!transformFlagsBuilder.Any());
......@@ -525,13 +532,19 @@ internal static void EncodeInternal(TypeSymbol type, int customModifiersCount, R
transformFlagsBuilder.Add(false);
}
// Native compiler encodes an extra transform flag, always false, for each custom modifier.
HandleCustomModifiers(customModifiersCount, transformFlagsBuilder);
type.VisitType(s_encodeDynamicTransform, transformFlagsBuilder);
if (addCustomModifierFlags)
{
// Native compiler encodes an extra transform flag, always false, for each custom modifier.
HandleCustomModifiers(customModifiersCount, transformFlagsBuilder);
type.VisitType((typeSymbol, builder, isNested) => AddFlags(typeSymbol, builder, isNested, addCustomModifierFlags:true), transformFlagsBuilder);
}
else
{
type.VisitType((typeSymbol, builder, isNested) => AddFlags(typeSymbol, builder, isNested, addCustomModifierFlags:false), transformFlagsBuilder);
}
}
private static readonly Func<TypeSymbol, ArrayBuilder<bool>, bool, bool> s_encodeDynamicTransform = (type, transformFlagsBuilder, isNestedNamedType) =>
private static bool AddFlags(TypeSymbol type, ArrayBuilder<bool> transformFlagsBuilder, bool isNestedNamedType, bool addCustomModifierFlags)
{
// Encode transforms flag for this type and it's custom modifiers (if any).
switch (type.TypeKind)
......@@ -541,12 +554,20 @@ internal static void EncodeInternal(TypeSymbol type, int customModifiersCount, R
break;
case TypeKind.Array:
HandleCustomModifiers(((ArrayTypeSymbol)type).CustomModifiers.Length, transformFlagsBuilder);
if (addCustomModifierFlags)
{
HandleCustomModifiers(((ArrayTypeSymbol)type).CustomModifiers.Length, transformFlagsBuilder);
}
transformFlagsBuilder.Add(false);
break;
case TypeKind.Pointer:
HandleCustomModifiers(((PointerTypeSymbol)type).CustomModifiers.Length, transformFlagsBuilder);
if (addCustomModifierFlags)
{
HandleCustomModifiers(((PointerTypeSymbol)type).CustomModifiers.Length, transformFlagsBuilder);
}
transformFlagsBuilder.Add(false);
break;
......@@ -569,7 +590,7 @@ internal static void EncodeInternal(TypeSymbol type, int customModifiersCount, R
// Continue walking types
return false;
};
}
private static void HandleCustomModifiers(int customModifiersCount, ArrayBuilder<bool> transformFlagsBuilder)
{
......
......@@ -65,8 +65,7 @@ internal static TypeSymbol CopyTypeCustomModifiers(TypeSymbol sourceType, TypeSy
// we can use it in place of this.Type. We do so by computing the dynamic transform flags that
// code gen uses and then passing them to the dynamic type decoder that metadata reading uses.
const int customModifierCount = 0;// Ignore custom modifiers, since we're not done copying them.
ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.Encode(destinationType, customModifierCount, refKind);
ImmutableArray<bool> flags = CSharpCompilation.DynamicTransformsEncoder.EncodeWithoutCustomModifierFlags(destinationType, refKind);
TypeSymbol resultType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(sourceType, containingAssembly, refKind, flags);
Debug.Assert(resultType.Equals(sourceType, ignoreCustomModifiersAndArraySizesAndLowerBounds: false, ignoreDynamic: true)); // Same custom modifiers as source type.
......
......@@ -59,13 +59,13 @@ internal sealed class SourceCustomEventSymbol : SourceEventSymbol
EventSymbol overriddenEvent = this.OverriddenEvent;
if ((object)overriddenEvent != null)
{
CopyEventCustomModifiers(overriddenEvent, ref _type);
CopyEventCustomModifiers(overriddenEvent, ref _type, ContainingAssembly);
}
}
}
else if ((object)explicitlyImplementedEvent != null)
{
CopyEventCustomModifiers(explicitlyImplementedEvent, ref _type);
CopyEventCustomModifiers(explicitlyImplementedEvent, ref _type, ContainingAssembly);
}
AccessorDeclarationSyntax addSyntax = null;
......
......@@ -501,7 +501,7 @@ public override string GetDocumentationCommentXml(CultureInfo preferredCulture =
return SourceDocumentationCommentUtils.GetAndCacheDocumentationComment(this, expandIncludes, ref _lazyDocComment);
}
protected static void CopyEventCustomModifiers(EventSymbol eventWithCustomModifiers, ref TypeSymbol type)
protected static void CopyEventCustomModifiers(EventSymbol eventWithCustomModifiers, ref TypeSymbol type, AssemblySymbol containingAssembly)
{
Debug.Assert((object)eventWithCustomModifiers != null);
......@@ -510,9 +510,9 @@ protected static void CopyEventCustomModifiers(EventSymbol eventWithCustomModifi
// We do an extra check before copying the type to handle the case where the overriding
// event (incorrectly) has a different type than the overridden event. In such cases,
// we want to retain the original (incorrect) type to avoid hiding the type given in source.
if (type.Equals(overriddenEventType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: false))
if (type.Equals(overriddenEventType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true))
{
type = overriddenEventType;
type = CustomModifierUtils.CopyTypeCustomModifiers(overriddenEventType, type, RefKind.None, containingAssembly);
}
}
......
......@@ -52,7 +52,7 @@ internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingTy
EventSymbol overriddenEvent = this.OverriddenEvent;
if ((object)overriddenEvent != null)
{
CopyEventCustomModifiers(overriddenEvent, ref _type);
CopyEventCustomModifiers(overriddenEvent, ref _type, ContainingAssembly);
}
}
......
......@@ -236,9 +236,9 @@ internal sealed class SourcePropertySymbol : PropertySymbol, IAttributeTargetSym
// We do an extra check before copying the type to handle the case where the overriding
// property (incorrectly) has a different type than the overridden property. In such cases,
// we want to retain the original (incorrect) type to avoid hiding the type given in source.
if (_lazyType.Equals(overriddenPropertyType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: false))
if (_lazyType.Equals(overriddenPropertyType, ignoreCustomModifiersAndArraySizesAndLowerBounds: true, ignoreDynamic: true))
{
_lazyType = overriddenPropertyType;
_lazyType = CustomModifierUtils.CopyTypeCustomModifiers(overriddenPropertyType, _lazyType, RefKind.None, this.ContainingAssembly);
}
_lazyParameters = CustomModifierUtils.CopyParameterCustomModifiers(overriddenOrImplementedProperty.Parameters, _lazyParameters, alsoCopyParamsModifier: isOverride);
......
......@@ -173,7 +173,7 @@ class CL3
{
public override void Test(int x)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}
";
......@@ -190,7 +190,7 @@ public override void Test(int x)
Assert.True(withoutModifiers.Equals(withModifiers, ignoreCustomModifiersAndArraySizesAndLowerBounds: true));
Assert.NotEqual(withoutModifiers, withModifiers);
CompileAndVerify(compilation, expectedOutput: "Overriden");
CompileAndVerify(compilation, expectedOutput: "Overridden");
}
[Fact, WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
......@@ -251,7 +251,7 @@ class CL3
{
public override void Test(ref int x)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}
";
......@@ -261,7 +261,7 @@ public override void Test(ref int x)
var test = cl3.GetMember<MethodSymbol>("Test");
Assert.Equal("void CL3.Test(ref System.Int32 modopt(System.Runtime.CompilerServices.IsConst) modopt(System.Runtime.CompilerServices.IsLong) x)", test.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput: "Overriden");
CompileAndVerify(compilation, expectedOutput: "Overridden");
}
[Fact, WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
......@@ -322,7 +322,7 @@ class CL3
{
public override void Test(ref int x)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}
";
......@@ -332,7 +332,7 @@ public override void Test(ref int x)
var test = cl3.GetMember<MethodSymbol>("Test");
Assert.Equal("void CL3.Test(ref modopt(System.Runtime.CompilerServices.IsConst) System.Int32 modopt(System.Runtime.CompilerServices.IsLong) x)", test.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput: "Overriden");
CompileAndVerify(compilation, expectedOutput: "Overridden");
}
[Fact, WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
......@@ -393,7 +393,7 @@ class CL3
{
public override void Test(ref int x)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}
";
......@@ -403,7 +403,7 @@ public override void Test(ref int x)
var test = cl3.GetMember<MethodSymbol>("Test");
Assert.Equal("void CL3.Test(ref System.Int32 modopt(System.Runtime.CompilerServices.IsLong) x)", test.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput: "Overriden");
CompileAndVerify(compilation, expectedOutput: "Overridden");
}
[Fact, WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
......@@ -465,7 +465,7 @@ class CL3
{
public override void Test(ref int x)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}
";
......@@ -475,7 +475,7 @@ public override void Test(ref int x)
var test = cl3.GetMember<MethodSymbol>("Test");
Assert.Equal("void CL3.Test(ref modopt(System.Runtime.CompilerServices.IsConst) System.Int32 modopt(System.Runtime.CompilerServices.IsVolatile) modopt(System.Runtime.CompilerServices.IsLong) x)", test.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput: "Overriden");
CompileAndVerify(compilation, expectedOutput: "Overridden");
}
[Fact, WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
......@@ -557,12 +557,12 @@ public override int Test
{
get
{
System.Console.WriteLine(""Get Overriden"");
System.Console.WriteLine(""Get Overridden"");
return 0;
}
set
{
System.Console.WriteLine(""Set Overriden"");
System.Console.WriteLine(""Set Overridden"");
}
}
}
......@@ -575,8 +575,8 @@ public override int Test
Assert.Equal("System.Int32 modopt(System.Runtime.CompilerServices.IsConst) modopt(System.Runtime.CompilerServices.IsLong) CL3.Test.get", test.GetMethod.ToTestDisplayString());
Assert.True(test.GetMethod.ReturnTypeCustomModifiers.SequenceEqual(test.SetMethod.Parameters.First().CustomModifiers));
CompileAndVerify(compilation, expectedOutput: @"Set Overriden
Get Overriden");
CompileAndVerify(compilation, expectedOutput: @"Set Overridden
Get Overridden");
}
[Fact, WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
......@@ -636,7 +636,7 @@ class CL3
{
public override void Test(int [] x)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}
";
......@@ -646,7 +646,7 @@ public override void Test(int [] x)
var test = cl3.GetMember<MethodSymbol>("Test");
Assert.Equal("void CL3.Test(System.Int32 modopt(System.Runtime.CompilerServices.IsConst) modopt(System.Runtime.CompilerServices.IsLong) [] x)", test.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput: "Overriden");
CompileAndVerify(compilation, expectedOutput: "Overridden");
}
[Fact, WorkItem(4163, "https://github.com/dotnet/roslyn/issues/4163")]
......@@ -1146,7 +1146,7 @@ class CL3 : CL2
{
public override void Test(Dictionary<dynamic, dynamic> a, Dictionary<dynamic, dynamic> b, Dictionary<dynamic, dynamic> c)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
foreach (var param in typeof(CL3).GetMethod(""Test"").GetParameters())
{
System.Console.WriteLine(param.GetCustomAttributesData().Single());
......@@ -1169,7 +1169,7 @@ static void Main()
Assert.Equal("void CL3.Test(System.Collections.Generic.Dictionary<dynamic modopt(System.Runtime.CompilerServices.IsConst), dynamic> a, System.Collections.Generic.Dictionary<dynamic, dynamic modopt(System.Runtime.CompilerServices.IsConst)> b, System.Collections.Generic.Dictionary<dynamic modopt(System.Runtime.CompilerServices.IsConst), dynamic modopt(System.Runtime.CompilerServices.IsConst)> c)", test.ToTestDisplayString());
};
CompileAndVerify(compilation, expectedOutput: @"Overriden
CompileAndVerify(compilation, expectedOutput: @"Overridden
[System.Runtime.CompilerServices.DynamicAttribute(new Boolean[3] { False, True, True })]
[System.Runtime.CompilerServices.DynamicAttribute(new Boolean[3] { False, True, True })]
[System.Runtime.CompilerServices.DynamicAttribute(new Boolean[3] { False, True, True })]",
......@@ -1298,7 +1298,7 @@ class CL3 : CL2
{
public override int Test(System.Func<int, int> x, int y)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
return x(y);
}
}
......@@ -1307,9 +1307,9 @@ public override int Test(System.Func<int, int> x, int y)
CompileAndVerify(compilation, expectedOutput: @"Test 1
Test 2
Overriden
Overridden
Test 3
Overriden
Overridden
Test 4
MyDelegate
Test 5
......@@ -1362,13 +1362,13 @@ class Test11 : Test1
{
public override void Test(int [,] c)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: @"Test
Overriden");
Overridden");
}
[ClrOnlyFact(ClrOnlyReason.Ilasm), WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")]
......@@ -1431,13 +1431,13 @@ class CL3 : CL2
{
public override void Test(int c)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: @"Test
Overriden");
Overridden");
}
[ClrOnlyFact(ClrOnlyReason.Ilasm), WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")]
......@@ -1500,13 +1500,13 @@ class CL3 : CL2
{
public override void Test(int c)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
}
}";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: @"Test
Overriden");
Overridden");
}
[ClrOnlyFact(ClrOnlyReason.Ilasm), WorkItem(5725, "https://github.com/dotnet/roslyn/issues/5725")]
......@@ -1570,14 +1570,14 @@ class CL3 : CL2
{
public override int[] Test(int c)
{
System.Console.WriteLine(""Overriden"");
System.Console.WriteLine(""Overridden"");
return null;
}
}";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, options: TestOptions.ReleaseExe);
CompileAndVerify(compilation, expectedOutput: @"Test
Overriden");
Overridden");
}
[ClrOnlyFact(ClrOnlyReason.Ilasm), WorkItem(5993, "https://github.com/dotnet/roslyn/issues/5993")]
......@@ -1690,5 +1690,231 @@ .maxstack 0
Assert.True(t1.Equals(t2, ignoreCustomModifiersAndArraySizesAndLowerBounds: true));
Assert.True(t2.Equals(t1, ignoreCustomModifiersAndArraySizesAndLowerBounds: true));
}
[Fact, WorkItem(7674, "https://github.com/dotnet/roslyn/issues/7674")]
public void PropertyWithDynamic()
{
var ilSource = @"
.class public auto ansi beforefieldinit CL1
extends [mscorlib] System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006: ret
} // end of method CL1`1::.ctor
.property instance object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[] modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
Test()
{
.get instance object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[] modopt([mscorlib]System.Runtime.CompilerServices.IsConst) CL1::get_Test()
.set instance void CL1::set_Test(object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[] modopt([mscorlib]System.Runtime.CompilerServices.IsConst))
} // end of property CL1::Test
.method public hidebysig newslot specialname virtual
instance object modopt([mscorlib]System.Runtime.CompilerServices.IsConst) [] modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
get_Test() cil managed
{
// Code size 2 (0x2)
.maxstack 1
IL_0000: ldarg.0
IL_0001: throw
} // end of method CL1::get_Test
.method public hidebysig newslot specialname virtual
instance void set_Test(object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[] modopt([mscorlib]System.Runtime.CompilerServices.IsConst) x) cil managed
{
// Code size 3 (0x3)
.maxstack 1
IL_0000: ldarg.0
IL_0001: throw
IL_0002: ret
} // end of method CL1::set_Test
} // end of class CL1
";
var source = @"
class Module1
{
static void Main()
{
CL1 x = new CL2();
x.Test = null;
var y = x.Test;
x = new CL3();
x.Test = null;
var z = x.Test;
}
}
class CL2
: CL1
{
public override dynamic[] Test
{
get
{
System.Console.WriteLine(""Get Overridden2"");
return null;
}
set
{
System.Console.WriteLine(""Set Overridden2"");
}
}
}
class CL3
: CL1
{
public override object[] Test
{
get
{
System.Console.WriteLine(""Get Overridden3"");
return null;
}
set
{
System.Console.WriteLine(""Set Overridden3"");
}
}
}
";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, new[] { CSharpRef, SystemCoreRef }, options: TestOptions.ReleaseExe);
var cl2 = compilation.GetTypeByMetadataName("CL2");
var test2 = cl2.GetMember<PropertySymbol>("Test");
Assert.Equal("dynamic modopt(System.Runtime.CompilerServices.IsConst) [] modopt(System.Runtime.CompilerServices.IsConst) CL2.Test { get; set; }",
test2.ToTestDisplayString());
var cl3 = compilation.GetTypeByMetadataName("CL3");
var test3 = cl3.GetMember<PropertySymbol>("Test");
Assert.Equal("System.Object modopt(System.Runtime.CompilerServices.IsConst) [] modopt(System.Runtime.CompilerServices.IsConst) CL3.Test { get; set; }",
test3.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput: @"Set Overridden2
Get Overridden2
Set Overridden3
Get Overridden3");
}
[Fact, WorkItem(7674, "https://github.com/dotnet/roslyn/issues/7674")]
public void EventWithDynamic()
{
var ilSource = @"
.class public auto ansi beforefieldinit CL1
extends [mscorlib] System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call instance void[mscorlib] System.Object::.ctor()
IL_0006: ret
} // end of method CL1`1::.ctor
.event class [mscorlib]System.Action`1<object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[]> Test
{
.addon instance void CL1::add_Test(class [mscorlib]System.Action`1<object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[]>)
.removeon instance void CL1::remove_Test(class [mscorlib]System.Action`1<object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[]>)
} // end of event CL1::Test
.method public hidebysig newslot specialname virtual
instance void add_Test(class [mscorlib]System.Action`1<object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[]> 'value') cil managed
{
// Code size 2 (0x2)
.maxstack 1
IL_0000: ldarg.0
IL_0001: throw
} // end of method CL1::get_Test
.method public hidebysig newslot specialname virtual
instance void remove_Test(class [mscorlib]System.Action`1<object modopt([mscorlib]System.Runtime.CompilerServices.IsConst)[]> 'value') cil managed
{
// Code size 3 (0x3)
.maxstack 1
IL_0000: ldarg.0
IL_0001: throw
IL_0002: ret
} // end of method CL1::set_Test
} // end of class CL1
";
var source = @"
using System;
class Module1
{
static void Main()
{
CL1 x = new CL2();
x.Test+= null;
x.Test-= null;
x = new CL3();
x.Test+= null;
x.Test-= null;
}
}
class CL2
: CL1
{
public override event Action<dynamic[]> Test
{
add
{
System.Console.WriteLine(""Add Overridden2"");
}
remove
{
System.Console.WriteLine(""Remove Overridden2"");
}
}
}
class CL3
: CL1
{
public override event Action<object[]> Test
{
add
{
System.Console.WriteLine(""Add Overridden3"");
}
remove
{
System.Console.WriteLine(""Remove Overridden3"");
}
}
}
";
var compilation = CreateCompilationWithCustomILSource(source, ilSource, new[] { CSharpRef, SystemCoreRef }, options: TestOptions.ReleaseExe);
var cl2 = compilation.GetTypeByMetadataName("CL2");
var test2 = cl2.GetMember<EventSymbol>("Test");
Assert.Equal("event System.Action<dynamic modopt(System.Runtime.CompilerServices.IsConst) []> CL2.Test",
test2.ToTestDisplayString());
var cl3 = compilation.GetTypeByMetadataName("CL3");
var test3 = cl3.GetMember<EventSymbol>("Test");
Assert.Equal("event System.Action<System.Object modopt(System.Runtime.CompilerServices.IsConst) []> CL3.Test",
test3.ToTestDisplayString());
CompileAndVerify(compilation, expectedOutput: @"Add Overridden2
Remove Overridden2
Add Overridden3
Remove Overridden3");
}
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册