Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 121 additions & 1 deletion Examples/RTTI/RTTI_component/Bindings/CSharp/RTTI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,126 @@ use of RTTI

namespace RTTI {

/// <summary>
/// Exception class for RTTI errors
/// </summary>
public class RTTIException : Exception
{
private readonly int _errorCode;
private readonly string _errorMessage;

/// <summary>
/// Initializes a new instance of the RTTIException class
/// </summary>
/// <param name="errorCode">The error code</param>
/// <param name="errorMessage">The error message</param>
public RTTIException(int errorCode, string errorMessage = "") : base(FormatMessage(errorCode, errorMessage))
{
_errorCode = errorCode;
_errorMessage = errorMessage;
}

/// <summary>
/// Gets the error code
/// </summary>
public int ErrorCode => _errorCode;

/// <summary>
/// Gets the custom error message
/// </summary>
public string ErrorMessage => _errorMessage;

/// <summary>
/// Gets the error name (constant name)
/// </summary>
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";
}
}
}

/// <summary>
/// Gets the error description (human-readable)
/// </summary>
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 {

Expand Down Expand Up @@ -89,7 +209,7 @@ public static void ThrowError(IntPtr Handle, Int32 errorCode)
}
}

throw new Exception(sMessage + "(# " + errorCode + ")");
throw new RTTIException(errorCode, sMessage);
}

/**
Expand Down
74 changes: 73 additions & 1 deletion Examples/RTTI/RTTI_component/Examples/CSharp/RTTI_Example.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down
104 changes: 103 additions & 1 deletion Source/buildbindingcsharp.go
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,108 @@ func buildBindingCSharpImplementation(component ComponentDefinition, w LanguageW
w.Writeln("namespace %s {", NameSpace)
w.Writeln("")

// Generate custom exception class
w.Writeln(" /// <summary>")
w.Writeln(" /// Exception class for %s errors", NameSpace)
w.Writeln(" /// </summary>")
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(" /// <summary>")
w.Writeln(" /// Initializes a new instance of the E%sException class", NameSpace)
w.Writeln(" /// </summary>")
w.Writeln(" /// <param name=\"errorCode\">The error code</param>")
w.Writeln(" /// <param name=\"errorMessage\">The error message</param>")
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(" /// <summary>")
w.Writeln(" /// Gets the error code")
w.Writeln(" /// </summary>")
w.Writeln(" public int ErrorCode => _errorCode;")
w.Writeln("")
w.Writeln(" /// <summary>")
w.Writeln(" /// Gets the custom error message")
w.Writeln(" /// </summary>")
w.Writeln(" public string ErrorMessage => _errorMessage;")
w.Writeln("")
w.Writeln(" /// <summary>")
w.Writeln(" /// Gets the error name (constant name)")
w.Writeln(" /// </summary>")
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(" /// <summary>")
w.Writeln(" /// Gets the error description (human-readable)")
w.Writeln(" /// </summary>")
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);")
Comment on lines +719 to +722
Copy link

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FormatMessage method creates duplicate code by repeating the same switch logic found in ErrorName and ErrorDescription properties. Consider reusing the existing properties instead of calling separate GetErrorName and GetErrorDescription methods.

Copilot uses AI. Check for mistakes.

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(" }")
Comment on lines +730 to +751
Copy link

Copilot AI Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GetErrorName and GetErrorDescription methods duplicate the switch logic already present in the ErrorName and ErrorDescription properties. This creates code duplication and maintenance overhead. These static methods are unnecessary since the instance properties provide the same functionality.

Suggested change
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(" }")

Copilot uses AI. Check for mistakes.

w.Writeln(" }")
w.Writeln("")

for i := 0; i < len(component.Enums); i++ {
enum := component.Enums[i]
w.Writeln(" public enum e%s {", enum.Name)
Expand Down Expand Up @@ -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("")
Expand Down
Loading