blazorinteger-arithmeticgeneric-type-parameters

Generic razor component allowing arithmetic operations


I want to create a razor component allowing to enter int or float numbers and increment or decrement them using a spin control. However, I have no idea to tell the Blazor generator / C# compiler how to handle an arithmetic operation on the value passed to the component, as the type is generic. What do I need to do to make such operations possible?

Here's my code:

@typeparam TValue

@code {
    [Parameter]
    public TValue Value { get; set; }

    [Parameter]
    public EventCallback<TValue> ValueChanged { get; set; }

    public void SpinUp() { Value += (TValue) 1; }

    public void SpinDown() { Value -= (TValue) 1; }
}

I understand that at compile time there is no information in the generic component whether TValue supports number arithmetic. The question is how to tell the compiler that TValue always has to be a numeric data type (e.g. by some restriction)?

I have omitted all HTML to keep this short, because it illustrates the problem. SpinUp() and SpinDown() are callback functions for a control consisting of two buttons you can click to increase or decrease the value in a numeric textbox.


Solution

  • Seems a bit long winded but:

    Happy for any ways to shorten it!

    @typeparam TValue
    <div>
        <button class="btn btn-danger" @onclick=SpinDown>-</button>
        <button class="btn btn-success" @onclick=SpinUp>+</button>
    </div>
    
    <div>
        Value = @Value?.ToString()
    </div>
    @code {
        [Parameter]
        public TValue? Value { get; set; }
    
        [Parameter]
        public EventCallback<TValue> ValueChanged { get; set; }
    
        private void SpinUp()
        {
            TValue value;
            switch (Value)
            {
                case int val:
                    val++;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case long val:
                    val++;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case short val:
                    val++;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case decimal val:
                    val++;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case float val:
                    val++;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case double val:
                    val++;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                default:
                    throw new Exception("Can't do maths operations on the type suplied");
    
            };
    
            ValueChanged.InvokeAsync(value);
        }
    
        private void SpinDown()
        {
            TValue value;
            switch (Value)
            {
                case int val:
                    val--;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case long val:
                    val--;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case short val:
                    val--;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case decimal val:
                    val--;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case float val:
                    val--;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                case double val:
                    val--;
                    value = (TValue)Convert.ChangeType(val, typeof(TValue));
                    break;
    
                default:
                    throw new Exception("Can't do maths operations on the type suplied");
    
            };
    
            ValueChanged.InvokeAsync(value);
        }
    }
    

    My test page:

    @page "/"
    
    <PageTitle>Index</PageTitle>
    
    <h1>Hello, world!</h1>
    
    Welcome to your new app.
    
    <SurveyPrompt Title="How is Blazor working for you?" />
    
    <Spinner @bind-Value=value/>
    
    <div>
        Value : @value.ToString()
    </div>
    @code {
        private double value = 0;
    }