Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 9, 2025

Then<U>() throws InvalidCastException when U doesn't implement IConvertible (e.g., custom record types). This broke in v1.4.0 when replacing Discard<U>().

Changes

  • Type conversion strategy: Check if U implements IConvertible at parser construction time
    • If yes: attempt Convert.ChangeType() with fallback to default(U) on failure
    • If no: directly return default(U) using the value constructor (avoids lambda overhead)
  • Performance: Move reflection check from parse-time to construction-time

Example

// Now works for custom types
public abstract record BaseExp;
var parser = commentParser.Then<BaseExp>();  // Previously threw InvalidCastException

// Still works for convertible types  
var intToDecimal = Literals.Integer().Then<decimal>();  // Converts int to decimal

Maintains backward compatibility with existing type conversions while enabling non-convertible types.

Original prompt

This section details on the original issue you should resolve

<issue_title>InvalidCastException when using .Then() where T is not IConvertible</issue_title>
<issue_description>Hi, after we updated to version 1.4.0 of parlot we started to get System.InvalidCastException : Object must implement IConvertible. exceptions in the code. It looks like it happens when using .Then<T>() where T is not IConvertible. Was this intentional, that Then now requires a IConvertible to discard the result?

Here is a snippet of test code which now fails after 1.4.0. The first case with the // A comment fails, but the other one is ok.

using Parlot.Fluent;
using static Parlot.Fluent.Parsers;

public class TestClass
{
    [Theory]
    [InlineData("""
        // A Comment
        var a = 'test'
        """)]
    [InlineData("""
        var a = 'test'
        """)]
    public void SimpleTest(string testString)
    {
        var commentParser = Terms.Text("//").And(AnyCharBefore(OneOf(Literals.Char('\n'), Literals.Char('\r'))));
        var varKeyword = Terms.Text("var");
        var identifier = Terms.Identifier();
        var equal = Terms.Char('=');
        var str = Terms.String();

        var expressionParser = varKeyword.And(identifier).And(equal).And(str).Then<BaseExp?>(a => new AssignExpression(a.Item2.ToString()!, a.Item4.ToString()!));

        var simpleParser = OneOf(commentParser.Then<BaseExp>(), expressionParser);

        var result = simpleParser.Parse(testString);
    }

    public abstract record BaseExp;

    public record AssignExpression(string Name, string Value) : BaseExp;
}

We were able to work around it by calling .Then(default(BaseExp)) instead, for ignoring the value</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Fix InvalidCastException when using .Then<T>() Fix InvalidCastException in Then<U>() for non-IConvertible types Nov 9, 2025
Copilot AI requested a review from sebastienros November 9, 2025 17:04
@sebastienros sebastienros marked this pull request as ready for review November 9, 2025 17:13
@sebastienros sebastienros merged commit e553de3 into main Nov 10, 2025
2 checks passed
@sebastienros sebastienros deleted the copilot/fix-invalidcastexception-then-method branch November 10, 2025 09:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

InvalidCastException when using .Then<T>() where T is not IConvertible

2 participants