Implement Castclass

This commit is contained in:
Smaug123
2025-06-27 11:41:41 +01:00
parent 5cf0789439
commit 1ebcd0b4f5
42 changed files with 856 additions and 132 deletions

View File

@@ -0,0 +1,18 @@
namespace WoofWare.PawPrint.Test
/// Result of executing the program using the real .NET runtime.
type RealRuntimeResult =
{
ExitCode : int
}
[<RequireQualifiedAccess>]
module RealRuntime =
/// Execute an assembly using the real .NET runtime and capture the result.
let executeWithRealRuntime (args : string[]) (assemblyBytes : byte array) : RealRuntimeResult =
let assy = System.Reflection.Assembly.Load assemblyBytes
let result = assy.EntryPoint.Invoke ((null : obj), [| args |]) |> unbox<int>
{
ExitCode = result
}

View File

@@ -32,7 +32,7 @@ module Roslyn =
|> Array.map (fun path -> MetadataReference.CreateFromFile path :> MetadataReference)
let compilationOptions =
CSharpCompilationOptions(OutputKind.ConsoleApplication).WithAllowUnsafe (true)
CSharpCompilationOptions(OutputKind.ConsoleApplication).WithAllowUnsafe true
let compilation =
CSharpCompilation.Create (

View File

@@ -30,5 +30,5 @@ type TestCase =
FileName : string
ExpectedReturnCode : int
NativeImpls : NativeImpls
LocalVariablesOfMain : CliType list
LocalVariablesOfMain : CliType list option
}

View File

@@ -1,47 +0,0 @@
namespace WoofWare.Pawprint.Test
open System
open System.Collections.Immutable
open System.IO
open FsUnitTyped
open NUnit.Framework
open WoofWare.PawPrint
open WoofWare.PawPrint.ExternImplementations
open WoofWare.PawPrint.Test
open WoofWare.DotnetRuntimeLocator
[<TestFixture>]
module TestHelloWorld =
let assy = typeof<RunResult>.Assembly
[<Test ; Explicit "This test doesn't run yet">]
let ``Can run Hello World`` () : unit =
let source = Assembly.getEmbeddedResourceAsString "WriteLine.cs" assy
let image = Roslyn.compile [ source ]
let messages, loggerFactory = LoggerFactory.makeTest ()
let dotnetRuntimes =
DotnetRuntime.SelectForDll assy.Location |> ImmutableArray.CreateRange
let impls = NativeImpls.PassThru ()
try
use peImage = new MemoryStream (image)
let terminalState, terminatingThread =
Program.run loggerFactory (Some "HelloWorld.cs") peImage dotnetRuntimes impls []
let exitCode =
match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with
| [] -> failwith "expected program to return 1, but it returned void"
| head :: _ ->
match head with
| EvalStackValue.Int32 i -> i
| _ -> failwith "TODO"
exitCode |> shouldEqual 0
with _ ->
for m in messages () do
Console.Error.WriteLine $"{m}"
reraise ()

View File

@@ -0,0 +1,123 @@
namespace WoofWare.Pawprint.Test
open System.Collections.Immutable
open System.IO
open FsUnitTyped
open NUnit.Framework
open WoofWare.DotnetRuntimeLocator
open WoofWare.PawPrint
open WoofWare.PawPrint.ExternImplementations
open WoofWare.PawPrint.Test
[<TestFixture>]
[<Parallelizable(ParallelScope.All)>]
module TestImpureCases =
let assy = typeof<RunResult>.Assembly
let unimplemented =
[
{
FileName = "WriteLine.cs"
ExpectedReturnCode = 1
NativeImpls = NativeImpls.PassThru ()
LocalVariablesOfMain = [] |> Some
}
]
let cases : TestCase list =
[
{
FileName = "InstaQuit.cs"
ExpectedReturnCode = 1
NativeImpls =
let mock = MockEnv.make ()
{ mock with
System_Environment =
{ System_EnvironmentMock.Empty with
GetProcessorCount =
fun thread state ->
let state =
state |> IlMachineState.pushToEvalStack' (EvalStackValue.Int32 1) thread
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
_Exit =
fun thread state ->
let state = state |> IlMachineState.loadArgument thread 0
ExecutionResult.Terminated (state, thread)
}
}
LocalVariablesOfMain = [] |> Some
}
]
[<TestCaseSource(nameof cases)>]
let ``Can evaluate C# files`` (case : TestCase) : unit =
let source = Assembly.getEmbeddedResourceAsString case.FileName assy
let image = Roslyn.compile [ source ]
let messages, loggerFactory = LoggerFactory.makeTest ()
let dotnetRuntimes =
DotnetRuntime.SelectForDll assy.Location |> ImmutableArray.CreateRange
use peImage = new MemoryStream (image)
try
let terminalState, terminatingThread =
Program.run loggerFactory (Some case.FileName) peImage dotnetRuntimes case.NativeImpls []
let exitCode =
match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with
| [] -> failwith "expected program to return a value, but it returned void"
| head :: _ ->
match head with
| EvalStackValue.Int32 i -> i
| ret -> failwith $"expected program to return an int, but it returned %O{ret}"
exitCode |> shouldEqual case.ExpectedReturnCode
let finalVariables =
terminalState.ThreadState.[terminatingThread].MethodState.LocalVariables
|> Seq.toList
match case.LocalVariablesOfMain with
| None -> ()
| Some expected -> finalVariables |> shouldEqual expected
with _ ->
for message in messages () do
System.Console.Error.WriteLine $"{message}"
reraise ()
[<TestCaseSource(nameof unimplemented)>]
[<Explicit "not yet implemented">]
let ``Can evaluate C# files, unimplemented`` (case : TestCase) : unit =
let source = Assembly.getEmbeddedResourceAsString case.FileName assy
let image = Roslyn.compile [ source ]
let messages, loggerFactory = LoggerFactory.makeTest ()
let dotnetRuntimes =
DotnetRuntime.SelectForDll assy.Location |> ImmutableArray.CreateRange
use peImage = new MemoryStream (image)
try
let terminalState, terminatingThread =
Program.run loggerFactory (Some case.FileName) peImage dotnetRuntimes case.NativeImpls []
let exitCode =
match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with
| [] -> failwith "expected program to return a value, but it returned void"
| head :: _ ->
match head with
| EvalStackValue.Int32 i -> i
| ret -> failwith $"expected program to return an int, but it returned %O{ret}"
exitCode |> shouldEqual case.ExpectedReturnCode
with _ ->
for message in messages () do
System.Console.Error.WriteLine $"{message}"
reraise ()

View File

@@ -11,7 +11,7 @@ open WoofWare.PawPrint.Test
[<TestFixture>]
[<Parallelizable(ParallelScope.All)>]
module TestCases =
module TestPureCases =
let assy = typeof<RunResult>.Assembly
let unimplemented =
@@ -20,7 +20,7 @@ module TestCases =
FileName = "Threads.cs"
ExpectedReturnCode = 3
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = []
LocalVariablesOfMain = [] |> Some
}
{
FileName = "ComplexTryCatch.cs"
@@ -50,18 +50,13 @@ module TestCases =
100001
]
|> List.map (fun i -> CliType.Numeric (CliNumericType.Int32 i))
}
{
FileName = "WriteLine.cs"
ExpectedReturnCode = 1
NativeImpls = NativeImpls.PassThru ()
LocalVariablesOfMain = []
|> Some
}
{
FileName = "ResizeArray.cs"
ExpectedReturnCode = 109
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 10) ]
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 10) ] |> Some
}
]
@@ -71,7 +66,127 @@ module TestCases =
FileName = "NoOp.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 1) ]
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 1) ] |> Some
}
{
FileName = "CastClassSimpleInheritance.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "IsInstSimpleInheritance.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassNull.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassArrayCovariance.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassToObject.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "IsinstPatternMatching.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassMultipleInterfaces.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassCrossAssembly.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassNestedTypes.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassGenerics.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassEnum.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassBoxing.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "IsinstBoxing.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassArray.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "IsinstArray.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "IsinstNull.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassInvalid.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "IsinstFailed.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "CastClassInterface.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "IsinstInterface.cs"
ExpectedReturnCode = 1
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = None
}
{
FileName = "Ldind.cs"
@@ -84,6 +199,7 @@ module TestCases =
// Return value
CliType.Numeric (CliNumericType.Int32 0)
]
|> Some
}
{
FileName = "CustomDelegate.cs"
@@ -100,6 +216,7 @@ module TestCases =
// ret
CliType.Numeric (CliNumericType.Int32 8)
]
|> Some
}
{
FileName = "ArgumentOrdering.cs"
@@ -114,6 +231,7 @@ module TestCases =
// return value
CliType.Numeric (CliNumericType.Int32 42)
]
|> Some
}
{
FileName = "BasicLock.cs"
@@ -136,6 +254,7 @@ module TestCases =
// return value
CliType.Numeric (CliNumericType.Int32 1)
]
|> Some
}
{
FileName = "TriangleNumber.cs"
@@ -152,29 +271,7 @@ module TestCases =
// Ret
CliType.Numeric (CliNumericType.Int32 10)
]
}
{
FileName = "InstaQuit.cs"
ExpectedReturnCode = 1
NativeImpls =
let mock = MockEnv.make ()
{ mock with
System_Environment =
{ System_EnvironmentMock.Empty with
GetProcessorCount =
fun thread state ->
let state =
state |> IlMachineState.pushToEvalStack' (EvalStackValue.Int32 1) thread
(state, WhatWeDid.Executed) |> ExecutionResult.Stepped
_Exit =
fun thread state ->
let state = state |> IlMachineState.loadArgument thread 0
ExecutionResult.Terminated (state, thread)
}
}
LocalVariablesOfMain = []
|> Some
}
{
FileName = "ExceptionWithNoOpFinally.cs"
@@ -187,12 +284,13 @@ module TestCases =
3
]
|> List.map (fun i -> CliType.Numeric (CliNumericType.Int32 i))
|> Some
}
{
FileName = "ExceptionWithNoOpCatch.cs"
ExpectedReturnCode = 10
NativeImpls = MockEnv.make ()
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 10) ]
LocalVariablesOfMain = [ CliType.Numeric (CliNumericType.Int32 10) ] |> Some
}
{
FileName = "TryCatchWithThrowInBody.cs"
@@ -205,6 +303,7 @@ module TestCases =
4
]
|> List.map (fun i -> CliType.Numeric (CliNumericType.Int32 i))
|> Some
}
]
@@ -223,6 +322,8 @@ module TestCases =
let terminalState, terminatingThread =
Program.run loggerFactory (Some case.FileName) peImage dotnetRuntimes case.NativeImpls []
let realResult = RealRuntime.executeWithRealRuntime [||] image
let exitCode =
match terminalState.ThreadState.[terminatingThread].MethodState.EvaluationStack.Values with
| [] -> failwith "expected program to return a value, but it returned void"
@@ -231,14 +332,17 @@ module TestCases =
| EvalStackValue.Int32 i -> i
| ret -> failwith $"expected program to return an int, but it returned %O{ret}"
realResult.ExitCode |> shouldEqual exitCode
exitCode |> shouldEqual case.ExpectedReturnCode
let finalVariables =
terminalState.ThreadState.[terminatingThread].MethodState.LocalVariables
|> Seq.toList
finalVariables |> shouldEqual case.LocalVariablesOfMain
match case.LocalVariablesOfMain with
| None -> ()
| Some expected -> finalVariables |> shouldEqual expected
with _ ->
for message in messages () do
System.Console.Error.WriteLine $"{message}"

View File

@@ -13,23 +13,44 @@
<Compile Include="LoggerFactory.fs" />
<Compile Include="Assembly.fs" />
<Compile Include="Roslyn.fs" />
<Compile Include="RealRuntime.fs" />
<Compile Include="TestHarness.fs"/>
<Compile Include="TestCases.fs" />
<Compile Include="TestHelloWorld.fs" />
<EmbeddedResource Include="sources\BasicLock.cs" />
<EmbeddedResource Include="sources\NoOp.cs" />
<EmbeddedResource Include="sources\ExceptionWithNoOpCatch.cs" />
<EmbeddedResource Include="sources\ExceptionWithNoOpFinally.cs" />
<EmbeddedResource Include="sources\TryCatchWithThrowInBody.cs" />
<EmbeddedResource Include="sources\ComplexTryCatch.cs" />
<EmbeddedResource Include="sources\TriangleNumber.cs" />
<EmbeddedResource Include="sources\WriteLine.cs" />
<EmbeddedResource Include="sources\InstaQuit.cs" />
<EmbeddedResource Include="sources\Threads.cs" />
<EmbeddedResource Include="sources\ResizeArray.cs" />
<EmbeddedResource Include="sources\ArgumentOrdering.cs" />
<EmbeddedResource Include="sources\CustomDelegate.cs" />
<EmbeddedResource Include="sources\Ldind.cs" />
<Compile Include="TestPureCases.fs" />
<Compile Include="TestImpureCases.fs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="sourcesPure\BasicLock.cs" />
<EmbeddedResource Include="sourcesPure\NoOp.cs" />
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpCatch.cs" />
<EmbeddedResource Include="sourcesPure\ExceptionWithNoOpFinally.cs" />
<EmbeddedResource Include="sourcesPure\TryCatchWithThrowInBody.cs" />
<EmbeddedResource Include="sourcesPure\ComplexTryCatch.cs" />
<EmbeddedResource Include="sourcesPure\TriangleNumber.cs" />
<EmbeddedResource Include="sourcesPure\Threads.cs" />
<EmbeddedResource Include="sourcesPure\ResizeArray.cs" />
<EmbeddedResource Include="sourcesPure\ArgumentOrdering.cs" />
<EmbeddedResource Include="sourcesPure\CastClassSimpleInheritance.cs" />
<EmbeddedResource Include="sourcesPure\IsInstSimpleInheritance.cs" />
<EmbeddedResource Include="sourcesPure\CastClassNull.cs" />
<EmbeddedResource Include="sourcesPure\CastClassArrayCovariance.cs" />
<EmbeddedResource Include="sourcesPure\CastClassToObject.cs" />
<EmbeddedResource Include="sourcesPure\IsinstPatternMatching.cs" />
<EmbeddedResource Include="sourcesPure\CastClassMultipleInterfaces.cs" />
<EmbeddedResource Include="sourcesPure\CastClassCrossAssembly.cs" />
<EmbeddedResource Include="sourcesPure\CastClassNestedTypes.cs" />
<EmbeddedResource Include="sourcesPure\CastClassGenerics.cs" />
<EmbeddedResource Include="sourcesPure\CastClassEnum.cs" />
<EmbeddedResource Include="sourcesPure\CastClassBoxing.cs" />
<EmbeddedResource Include="sourcesPure\IsinstBoxing.cs" />
<EmbeddedResource Include="sourcesPure\CastClassArray.cs" />
<EmbeddedResource Include="sourcesPure\IsinstArray.cs" />
<EmbeddedResource Include="sourcesPure\IsinstNull.cs" />
<EmbeddedResource Include="sourcesPure\CastClassInvalid.cs" />
<EmbeddedResource Include="sourcesPure\IsinstFailed.cs" />
<EmbeddedResource Include="sourcesPure\CastClassInterface.cs" />
<EmbeddedResource Include="sourcesPure\IsinstInterface.cs" />
<EmbeddedResource Include="sourcesPure\CustomDelegate.cs" />
<EmbeddedResource Include="sourcesPure\Ldind.cs" />
</ItemGroup>
<ItemGroup>
@@ -37,14 +58,19 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FsUnit" Version="7.0.1"/>
<PackageReference Include="FsUnit" Version="7.1.1"/>
<PackageReference Include="NUnit3TestAdapter" Version="5.0.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1"/>
<PackageReference Include="NUnit" Version="4.3.2"/>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.14.0"/>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.6" />
<PackageReference Include="WoofWare.DotnetRuntimeLocator" Version="0.3.2"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="sourcesImpure\WriteLine.cs" />
<EmbeddedResource Include="sourcesImpure\InstaQuit.cs" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,12 @@
public class Program
{
public static int Main(string[] args)
{
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
// Cast array to System.Array - should succeed
System.Array array = (System.Array)numbers;
return array.Length;
}
}

View File

@@ -0,0 +1,28 @@
public class Program
{
public struct Counter
{
public int Count;
public Counter(int count)
{
Count = count;
}
}
public static int Main(string[] args)
{
Counter counter = new Counter(42);
// Box the value type
object boxed = counter;
// Check if boxed value is System.ValueType
if (boxed is System.ValueType)
{
return 42;
}
return 0;
}
}

View File

@@ -0,0 +1,30 @@
public class Program
{
public struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
}
public static int Main(string[] args)
{
Point p = new Point(10, 32);
// Box the value type
object boxed = p;
// Cast boxed value type to object (should succeed)
object obj = (object)boxed;
// Unbox
Point unboxed = (Point)obj;
return unboxed.X + unboxed.Y;
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
public class Program
{
public static int Main(string[] args)
{
// Using types from System.Collections.Generic assembly
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
// Cast to interface from another assembly
IEnumerable<int> enumerable = (IEnumerable<int>)list;
int count = 0;
foreach (var item in enumerable)
{
count++;
}
return count == 5 ? 42 : 0;
}
}

View File

@@ -0,0 +1,25 @@
public class Program
{
public enum Color
{
Red = 1,
Green = 2,
Blue = 42
}
public static int Main(string[] args)
{
Color myColor = Color.Blue;
// Box enum value
object boxed = myColor;
// Cast to System.Enum
System.Enum enumValue = (System.Enum)boxed;
// Cast back to specific enum
Color unboxed = (Color)enumValue;
return (int)unboxed;
}
}

View File

@@ -0,0 +1,23 @@
public class Program
{
public class Container<T>
{
public T Value { get; set; }
}
public static int Main(string[] args)
{
Container<int> intContainer = new Container<int> { Value = 42 };
// Cast generic type to object
object obj = (object)intContainer;
// Check type and cast back
if (obj is Container<int> container)
{
return container.Value;
}
return 0;
}
}

View File

@@ -0,0 +1,25 @@
public class Program
{
public interface ICalculator
{
int Calculate(int x, int y);
}
public class Adder : ICalculator
{
public int Calculate(int x, int y)
{
return x + y;
}
}
public static int Main(string[] args)
{
Adder adder = new Adder();
// Cast to interface - should succeed
ICalculator calc = (ICalculator)adder;
return calc.Calculate(10, 32);
}
}

View File

@@ -0,0 +1,31 @@
public class Program
{
public class Cat
{
public string Name { get; set; }
}
public class Dog
{
public string Name { get; set; }
}
public static int Main(string[] args)
{
try
{
object cat = new Cat { Name = "Whiskers" };
// Invalid cast - should throw InvalidCastException
Dog dog = (Dog)cat;
// Should not reach here
return 0;
}
catch (System.InvalidCastException)
{
// Expected exception caught
return 42;
}
}
}

View File

@@ -0,0 +1,40 @@
public class Program
{
public interface IReadable
{
string Read();
}
public interface IWritable
{
void Write(string data);
}
public class File : IReadable, IWritable
{
private string content = "Hello";
public string Read()
{
return content;
}
public void Write(string data)
{
content = data;
}
}
public static int Main(string[] args)
{
File file = new File();
// Cast to first interface
IReadable readable = (IReadable)file;
// Cast to second interface
IWritable writable = (IWritable)file;
return readable != null && writable != null ? 42 : 0;
}
}

View File

@@ -0,0 +1,23 @@
public class Program
{
public class Outer
{
public class Inner
{
public int Value { get; set; }
}
}
public static int Main(string[] args)
{
Outer.Inner inner = new Outer.Inner { Value = 42 };
// Cast nested type to object
object obj = (object)inner;
// Cast back
Outer.Inner casted = (Outer.Inner)obj;
return casted.Value;
}
}

View File

@@ -0,0 +1,17 @@
public class Program
{
public class MyClass
{
public int Value { get; set; }
}
public static int Main(string[] args)
{
MyClass obj = null;
// Cast null reference - should succeed and remain null
object result = (object)obj;
return result == null ? 42 : 0;
}
}

View File

@@ -0,0 +1,22 @@
public class Program
{
public class Animal
{
public int Age { get; set; }
}
public class Dog : Animal
{
public string Name { get; set; }
}
public static int Main(string[] args)
{
Dog myDog = new Dog { Age = 5, Name = "Rex" };
// Cast to base class - should succeed
Animal animal = (Animal)myDog;
return animal.Age;
}
}

View File

@@ -0,0 +1,18 @@
public class Program
{
public class CustomClass
{
public int Id { get; set; }
}
public static int Main(string[] args)
{
CustomClass custom = new CustomClass { Id = 42 };
// Everything can be cast to System.Object
System.Object obj = (System.Object)custom;
// Verify it's the same object
return obj != null && obj == custom ? 42 : 0;
}
}

View File

@@ -0,0 +1,25 @@
public class Program
{
public class Vehicle
{
public int Wheels { get; set; }
}
public class Car : Vehicle
{
public string Model { get; set; }
}
public static int Main(string[] args)
{
Car myCar = new Car { Wheels = 4, Model = "Tesla" };
// 'is' operator uses isinst instruction
if (myCar is Vehicle)
{
return 42;
}
return 0;
}
}

View File

@@ -0,0 +1,15 @@
public class Program
{
public static int Main(string[] args)
{
string[] names = new string[] { "Alice", "Bob", "Charlie" };
// Check if array is System.Array
if (names is System.Array)
{
return 42;
}
return 0;
}
}

View File

@@ -0,0 +1,28 @@
public class Program
{
public struct Counter
{
public int Count;
public Counter(int count)
{
Count = count;
}
}
public static int Main(string[] args)
{
Counter counter = new Counter(42);
// Box the value type
object boxed = counter;
// Check if boxed value is System.ValueType
if (boxed is System.ValueType)
{
return 42;
}
return 0;
}
}

View File

@@ -0,0 +1,22 @@
public class Program
{
public class Bird
{
public bool CanFly { get; set; }
}
public class Fish
{
public bool CanSwim { get; set; }
}
public static int Main(string[] args)
{
Bird sparrow = new Bird { CanFly = true };
// This should fail and return null (not throw)
Fish fish = sparrow as Fish;
return fish == null ? 42 : 0;
}
}

View File

@@ -0,0 +1,27 @@
public class Program
{
public interface IDisposable
{
void Dispose();
}
public class Resource : IDisposable
{
public int Id { get; set; }
public void Dispose()
{
// Cleanup
}
}
public static int Main(string[] args)
{
Resource resource = new Resource { Id = 42 };
// 'as' operator uses isinst instruction
IDisposable disposable = resource as IDisposable;
return disposable != null ? resource.Id : 0;
}
}

View File

@@ -0,0 +1,17 @@
public class Program
{
public class MyType
{
public int Value { get; set; }
}
public static int Main(string[] args)
{
MyType obj = null;
// isinst on null should return null
object result = obj as object;
return result == null ? 42 : 0;
}
}

View File

@@ -0,0 +1,40 @@
public class Program
{
public abstract class Shape
{
public abstract double GetArea();
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double GetArea()
{
return 3.14 * Radius * Radius;
}
}
public class Square : Shape
{
public double Side { get; set; }
public override double GetArea()
{
return Side * Side;
}
}
public static int Main(string[] args)
{
Shape shape = new Circle { Radius = 10 };
// Pattern matching uses isinst
if (shape is Circle circle)
{
return (int)circle.Radius;
}
return 0;
}
}

View File

@@ -26,8 +26,8 @@
},
{
"pname": "FsUnit",
"version": "7.0.1",
"hash": "sha256-K85CIdxMeFSHEKZk6heIXp/oFjWAn7dBILKrw49pJUY="
"version": "7.1.1",
"hash": "sha256-UMCEGKxQ4ytjmPuVpiNaAPbi3RQH9gqa61JJIUS/6hg="
},
{
"pname": "Microsoft.ApplicationInsights",
@@ -61,38 +61,48 @@
},
{
"pname": "Microsoft.CodeAnalysis.Analyzers",
"version": "3.3.4",
"hash": "sha256-qDzTfZBSCvAUu9gzq2k+LOvh6/eRvJ9++VCNck/ZpnE="
"version": "3.11.0",
"hash": "sha256-hQ2l6E6PO4m7i+ZsfFlEx+93UsLPo4IY3wDkNG11/Sw="
},
{
"pname": "Microsoft.CodeAnalysis.Common",
"version": "4.8.0",
"hash": "sha256-3IEinVTZq6/aajMVA8XTRO3LTIEt0PuhGyITGJLtqz4="
"version": "4.14.0",
"hash": "sha256-ne/zxH3GqoGB4OemnE8oJElG5mai+/67ASaKqwmL2BE="
},
{
"pname": "Microsoft.CodeAnalysis.CSharp",
"version": "4.8.0",
"hash": "sha256-MmOnXJvd/ezs5UPcqyGLnbZz5m+VedpRfB+kFZeeqkU="
"version": "4.14.0",
"hash": "sha256-5Mzj3XkYYLkwDWh17r1NEXSbXwwWYQPiOmkSMlgo1JY="
},
{
"pname": "Microsoft.CodeCoverage",
"version": "17.13.0",
"hash": "sha256-GKrIxeyQo5Az1mztfQgea1kGtJwonnNOrXK/0ULfu8o="
"version": "17.14.1",
"hash": "sha256-f8QytG8GvRoP47rO2KEmnDLxIpyesaq26TFjDdW40Gs="
},
{
"pname": "Microsoft.Extensions.DependencyInjection.Abstractions",
"version": "9.0.2",
"hash": "sha256-WoTLgw/OlXhgN54Szip0Zpne7i/YTXwZ1ZLCPcHV6QM="
},
{
"pname": "Microsoft.Extensions.DependencyInjection.Abstractions",
"version": "9.0.6",
"hash": "sha256-40rY38OwSqueIWr/KMvJX9u+vipN+AaRQ6eNCZLqrog="
},
{
"pname": "Microsoft.Extensions.Logging.Abstractions",
"version": "9.0.2",
"hash": "sha256-mCxeuc+37XY0bmZR+z4p1hrZUdTZEg+FRcs/m6dAQDU="
},
{
"pname": "Microsoft.Extensions.Logging.Abstractions",
"version": "9.0.6",
"hash": "sha256-lhOMYT4+hua7SlgASGFBDhOkrNOsy35WyIxU3nVsD08="
},
{
"pname": "Microsoft.NET.Test.Sdk",
"version": "17.13.0",
"hash": "sha256-sc2wvyV8cGm1FrNP2GGHEI584RCvRPu15erYCsgw5QY="
"version": "17.14.1",
"hash": "sha256-mZUzDFvFp7x1nKrcnRd0hhbNu5g8EQYt8SKnRgdhT/A="
},
{
"pname": "Microsoft.NETCore.App.Host.linux-arm64",
@@ -191,13 +201,13 @@
},
{
"pname": "Microsoft.TestPlatform.ObjectModel",
"version": "17.13.0",
"hash": "sha256-6S0fjfj8vA+h6dJVNwLi6oZhYDO/I/6hBZaq2VTW+Uk="
"version": "17.14.1",
"hash": "sha256-QMf6O+w0IT+16Mrzo7wn+N20f3L1/mDhs/qjmEo1rYs="
},
{
"pname": "Microsoft.TestPlatform.TestHost",
"version": "17.13.0",
"hash": "sha256-L/CJzou7dhmShUgXq3aXL3CaLTJll17Q+JY2DBdUUpo="
"version": "17.14.1",
"hash": "sha256-1cxHWcvHRD7orQ3EEEPPxVGEkTpxom1/zoICC9SInJs="
},
{
"pname": "Myriad.Core",
@@ -216,8 +226,8 @@
},
{
"pname": "Newtonsoft.Json",
"version": "13.0.1",
"hash": "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo="
"version": "13.0.3",
"hash": "sha256-hy/BieY4qxBWVVsDqqOPaLy1QobiIapkbrESm6v2PHc="
},
{
"pname": "NUnit",
@@ -246,8 +256,8 @@
},
{
"pname": "System.Collections.Immutable",
"version": "7.0.0",
"hash": "sha256-9an2wbxue2qrtugYES9awshQg+KfJqajhnhs45kQIdk="
"version": "9.0.0",
"hash": "sha256-+6q5VMeoc5bm4WFsoV6nBXA9dV5pa/O4yW+gOdi8yac="
},
{
"pname": "System.Diagnostics.DiagnosticSource",
@@ -281,19 +291,19 @@
},
{
"pname": "System.Reflection.Metadata",
"version": "7.0.0",
"hash": "sha256-GwAKQhkhPBYTqmRdG9c9taqrKSKDwyUgOEhWLKxWNPI="
"version": "8.0.0",
"hash": "sha256-dQGC30JauIDWNWXMrSNOJncVa1umR1sijazYwUDdSIE="
},
{
"pname": "System.Reflection.Metadata",
"version": "9.0.0",
"hash": "sha256-avEWbcCh7XgpsSesnR3/SgxWi/6C5OxjR89Jf/SfRjQ="
},
{
"pname": "System.Runtime",
"version": "4.3.1",
"hash": "sha256-R9T68AzS1PJJ7v6ARz9vo88pKL1dWqLOANg4pkQjkA0="
},
{
"pname": "System.Runtime.CompilerServices.Unsafe",
"version": "6.0.0",
"hash": "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I="
},
{
"pname": "TypeEquality",
"version": "0.3.0",