diff --git a/Examples/RTTI/RTTI_component/Bindings/CSharp/RTTI.cs b/Examples/RTTI/RTTI_component/Bindings/CSharp/RTTI.cs index c8a9e0bd..94a9e564 100644 --- a/Examples/RTTI/RTTI_component/Bindings/CSharp/RTTI.cs +++ b/Examples/RTTI/RTTI_component/Bindings/CSharp/RTTI.cs @@ -19,6 +19,126 @@ use of RTTI namespace RTTI { + /// + /// Exception class for RTTI errors + /// + public class RTTIException : Exception + { + private readonly int _errorCode; + private readonly string _errorMessage; + + /// + /// Initializes a new instance of the RTTIException class + /// + /// The error code + /// The error message + public RTTIException(int errorCode, string errorMessage = "") : base(FormatMessage(errorCode, errorMessage)) + { + _errorCode = errorCode; + _errorMessage = errorMessage; + } + + /// + /// Gets the error code + /// + public int ErrorCode => _errorCode; + + /// + /// Gets the custom error message + /// + public string ErrorMessage => _errorMessage; + + /// + /// Gets the error name (constant name) + /// + public string ErrorName + { + get + { + switch (_errorCode) + { + case 0: return "SUCCESS"; + case 1: return "NOTIMPLEMENTED"; + case 2: return "INVALIDPARAM"; + case 3: return "INVALIDCAST"; + case 4: return "BUFFERTOOSMALL"; + case 5: return "GENERICEXCEPTION"; + case 6: return "COULDNOTLOADLIBRARY"; + case 7: return "COULDNOTFINDLIBRARYEXPORT"; + case 8: return "INCOMPATIBLEBINARYVERSION"; + default: return "UNKNOWN"; + } + } + } + + /// + /// Gets the error description (human-readable) + /// + public string ErrorDescription + { + get + { + switch (_errorCode) + { + case 0: return "success"; + case 1: return "functionality not implemented"; + case 2: return "an invalid parameter was passed"; + case 3: return "a type cast failed"; + case 4: return "a provided buffer is too small"; + case 5: return "a generic exception occurred"; + case 6: return "the library could not be loaded"; + case 7: return "a required exported symbol could not be found in the library"; + case 8: return "the version of the binary interface does not match the bindings interface"; + default: return "unknown error"; + } + } + } + + private static string FormatMessage(int errorCode, string errorMessage) + { + string errorName = GetErrorName(errorCode); + string errorDesc = GetErrorDescription(errorCode); + if (!string.IsNullOrEmpty(errorMessage)) + return $"RTTIException {errorName} ({errorCode}): {errorDesc} - {errorMessage}"; + else + return $"RTTIException {errorName} ({errorCode}): {errorDesc}"; + } + + private static string GetErrorName(int errorCode) + { + switch (errorCode) + { + case 0: return "SUCCESS"; + case 1: return "NOTIMPLEMENTED"; + case 2: return "INVALIDPARAM"; + case 3: return "INVALIDCAST"; + case 4: return "BUFFERTOOSMALL"; + case 5: return "GENERICEXCEPTION"; + case 6: return "COULDNOTLOADLIBRARY"; + case 7: return "COULDNOTFINDLIBRARYEXPORT"; + case 8: return "INCOMPATIBLEBINARYVERSION"; + default: return "UNKNOWN"; + } + } + + private static string GetErrorDescription(int errorCode) + { + switch (errorCode) + { + case 0: return "success"; + case 1: return "functionality not implemented"; + case 2: return "an invalid parameter was passed"; + case 3: return "a type cast failed"; + case 4: return "a provided buffer is too small"; + case 5: return "a generic exception occurred"; + case 6: return "the library could not be loaded"; + case 7: return "a required exported symbol could not be found in the library"; + case 8: return "the version of the binary interface does not match the bindings interface"; + default: return "unknown error"; + } + } + } + namespace Internal { @@ -89,7 +209,7 @@ public static void ThrowError(IntPtr Handle, Int32 errorCode) } } - throw new Exception(sMessage + "(# " + errorCode + ")"); + throw new RTTIException(errorCode, sMessage); } /** diff --git a/Examples/RTTI/RTTI_component/Examples/CSharp/RTTI_Example.cs b/Examples/RTTI/RTTI_component/Examples/CSharp/RTTI_Example.cs index 0d941855..f37d2bf8 100644 --- a/Examples/RTTI/RTTI_component/Examples/CSharp/RTTI_Example.cs +++ b/Examples/RTTI/RTTI_component/Examples/CSharp/RTTI_Example.cs @@ -19,8 +19,68 @@ namespace RTTI_Example { class RTTI_Example { + static void TestExceptionMethods() + { + Console.WriteLine("Testing RTTI Exception Methods..."); + + // Test by calling a method with invalid parameters to trigger an exception + try + { + // This should throw an ERTTIException with INVALIDPARAM error + // Manually throw an exception to test the exception properties + throw new RTTI.ERTTIException(2, "rtti exception"); + } + catch (RTTI.ERTTIException ex) + { + Console.WriteLine("+ Successfully caught ERTTIException"); + + // Test the new exception properties + int errorCode = ex.ErrorCode; + string errorMessage = ex.ErrorMessage; + string errorName = ex.ErrorName; + string errorDescription = ex.ErrorDescription; + string baseMessage = ex.Message; // Base exception message from Exception class + + Console.WriteLine($" Error Code: {errorCode}"); + Console.WriteLine($" Error Message (custom): '{errorMessage}'"); + Console.WriteLine($" Error Name: {errorName}"); + Console.WriteLine($" Error Description: {errorDescription}"); + Console.WriteLine($" Base Message: '{baseMessage}'"); + + // Verify error details - expecting INVALIDPARAM (code 2) + if (errorCode != 2) + throw new Exception($"Expected error code 2 (INVALIDPARAM), got {errorCode}"); + if (errorName != "INVALIDPARAM") + throw new Exception($"Expected 'INVALIDPARAM', got '{errorName}'"); + if (errorDescription != "an invalid parameter was passed") + throw new Exception($"Expected invalid parameter error description, got '{errorDescription}'"); + + // Test string representation + string exceptionStr = ex.ToString(); + if (!exceptionStr.Contains("ERTTIException")) + throw new Exception($"String representation should contain 'ERTTIException', got '{exceptionStr}'"); + if (!exceptionStr.Contains(errorCode.ToString())) + throw new Exception($"String representation should contain error code, got '{exceptionStr}'"); + + Console.WriteLine("+ All exception property tests passed!"); + } + } + static void Main() { + Console.WriteLine("RTTI C# Example with Exception Testing"); + Console.WriteLine("=================================================="); + Console.WriteLine(); + + // Test exception methods first + Console.WriteLine("Testing Exception Methods:"); + Console.WriteLine("------------------------------"); + TestExceptionMethods(); + Console.WriteLine(); + + // Then run the main example + Console.WriteLine("Running Main RTTI Example:"); + Console.WriteLine("------------------------------"); try { UInt32 nMajor, nMinor, nMicro; @@ -96,9 +156,21 @@ static void Main() if (!(Animal.GetHandle() != IntPtr.Zero)) throw new Exception("Wrong data"); if (!(Animal.Name().Equals("Gary Giraffe"))) throw new Exception("Wrong data"); if (!(Animal is RTTI.CGiraffe)) throw new Exception("Wrong data"); - + Animal = Iterator.GetNextAnimal(); if (!(Animal.GetHandle() == IntPtr.Zero)) throw new Exception("Wrong data"); + + Console.WriteLine("+ Main example completed successfully!"); + } + catch (RTTI.ERTTIException ex) + { + Console.WriteLine("RTTI Exception occurred:"); + Console.WriteLine($" Error Code: {ex.ErrorCode}"); + Console.WriteLine($" Error Message: '{ex.ErrorMessage}'"); + Console.WriteLine($" Error Name: {ex.ErrorName}"); + Console.WriteLine($" Error Description: {ex.ErrorDescription}"); + Console.WriteLine($" Full Exception: {ex}"); + System.Environment.Exit(1); } catch (Exception e) { diff --git a/Source/buildbindingcsharp.go b/Source/buildbindingcsharp.go index a0776339..13ed675d 100644 --- a/Source/buildbindingcsharp.go +++ b/Source/buildbindingcsharp.go @@ -650,6 +650,108 @@ func buildBindingCSharpImplementation(component ComponentDefinition, w LanguageW w.Writeln("namespace %s {", NameSpace) w.Writeln("") + // Generate custom exception class + w.Writeln(" /// ") + w.Writeln(" /// Exception class for %s errors", NameSpace) + w.Writeln(" /// ") + w.Writeln(" public class E%sException : Exception", NameSpace) + w.Writeln(" {") + w.Writeln(" private readonly int _errorCode;") + w.Writeln(" private readonly string _errorMessage;") + w.Writeln("") + w.Writeln(" /// ") + w.Writeln(" /// Initializes a new instance of the E%sException class", NameSpace) + w.Writeln(" /// ") + w.Writeln(" /// The error code") + w.Writeln(" /// The error message") + w.Writeln(" public E%sException(int errorCode, string errorMessage = \"\") : base(FormatMessage(errorCode, errorMessage))", NameSpace) + w.Writeln(" {") + w.Writeln(" _errorCode = errorCode;") + w.Writeln(" _errorMessage = errorMessage;") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" /// ") + w.Writeln(" /// Gets the error code") + w.Writeln(" /// ") + w.Writeln(" public int ErrorCode => _errorCode;") + w.Writeln("") + w.Writeln(" /// ") + w.Writeln(" /// Gets the custom error message") + w.Writeln(" /// ") + w.Writeln(" public string ErrorMessage => _errorMessage;") + w.Writeln("") + w.Writeln(" /// ") + w.Writeln(" /// Gets the error name (constant name)") + w.Writeln(" /// ") + w.Writeln(" public string ErrorName") + w.Writeln(" {") + w.Writeln(" get") + w.Writeln(" {") + w.Writeln(" switch (_errorCode)") + w.Writeln(" {") + w.Writeln(" case 0: return \"SUCCESS\";") + for _, errorDef := range component.Errors.Errors { + w.Writeln(" case %d: return \"%s\";", errorDef.Code, errorDef.Name) + } + w.Writeln(" default: return \"UNKNOWN\";") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" /// ") + w.Writeln(" /// Gets the error description (human-readable)") + w.Writeln(" /// ") + w.Writeln(" public string ErrorDescription") + w.Writeln(" {") + w.Writeln(" get") + w.Writeln(" {") + w.Writeln(" switch (_errorCode)") + w.Writeln(" {") + w.Writeln(" case 0: return \"success\";") + for _, errorDef := range component.Errors.Errors { + w.Writeln(" case %d: return \"%s\";", errorDef.Code, errorDef.Description) + } + w.Writeln(" default: return \"unknown error\";") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" private static string FormatMessage(int errorCode, string errorMessage)") + w.Writeln(" {") + w.Writeln(" string errorName = GetErrorName(errorCode);") + w.Writeln(" string errorDesc = GetErrorDescription(errorCode);") + w.Writeln(" if (!string.IsNullOrEmpty(errorMessage))") + w.Writeln(" return $\"E%sException {errorName} ({errorCode}): {errorDesc} - {errorMessage}\";", NameSpace) + w.Writeln(" else") + w.Writeln(" return $\"E%sException {errorName} ({errorCode}): {errorDesc}\";", NameSpace) + w.Writeln(" }") + w.Writeln("") + w.Writeln(" private static string GetErrorName(int errorCode)") + w.Writeln(" {") + w.Writeln(" switch (errorCode)") + w.Writeln(" {") + w.Writeln(" case 0: return \"SUCCESS\";") + for _, errorDef := range component.Errors.Errors { + w.Writeln(" case %d: return \"%s\";", errorDef.Code, errorDef.Name) + } + w.Writeln(" default: return \"UNKNOWN\";") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + w.Writeln(" private static string GetErrorDescription(int errorCode)") + w.Writeln(" {") + w.Writeln(" switch (errorCode)") + w.Writeln(" {") + w.Writeln(" case 0: return \"success\";") + for _, errorDef := range component.Errors.Errors { + w.Writeln(" case %d: return \"%s\";", errorDef.Code, errorDef.Description) + } + w.Writeln(" default: return \"unknown error\";") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln(" }") + w.Writeln("") + for i := 0; i < len(component.Enums); i++ { enum := component.Enums[i] w.Writeln(" public enum e%s {", enum.Name) @@ -967,7 +1069,7 @@ func buildBindingCSharpImplementation(component ComponentDefinition, w LanguageW w.Writeln(" }") w.Writeln("") } - w.Writeln(" throw new Exception(sMessage + \"(# \" + errorCode + \")\");") + w.Writeln(" throw new E%sException(errorCode, sMessage);", NameSpace) w.Writeln(" }") w.Writeln("")