HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcsharpMinor

Dynamically convert property to different data type

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
dynamicallyconverttypedifferentpropertydata

Problem

The code finds marked attributes and parses them according to the attribute type.

Is it possible to simplify this logic? Is there generic way to do it? Please suggest some way to optimise this code. All the data type of Product class will be string. I'm getting product input as XML directly converting serialized data to a class with decimal, int, float will not give proper error message.

If there is list of items it will throw error in XMl and we won't know which row has caused the error.

```
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace TestSolution
{
public interface ICustomParser
{
bool Parse(string input);
}

public class DecimalParserAttribute : Attribute, ICustomParser
{
public bool Parse(string input)
{
if (input == null) return false;

decimal decimalValue;

return decimal.TryParse(input, out decimalValue);
}
}

public class intParserAttribute : Attribute, ICustomParser
{
public bool Parse(string input)
{
if (input == null) return false;

int intValue;

return int.TryParse(input, out intValue);
}
}

public class Product
{
[DecimalParser]
public string Weight { get; set; }

[intParser]
public string NoOfItems { get; set; }

[intParser]
public string GRodes { get; set; }

[intParser]
public string WRodes { get; set; }
}

class Program
{
static void Main(string[] args)
{

var sb = Validate(new Product() { NoOfItems = "1", GRodes = "4", Weight = "5", WRodes = "23" });

Console.WriteLine(sb);
sb = Validate(new Product() { NoOfItems = "1", GRodes = "4w", Weight = "5", WRodes = "23" });

Console.WriteLine(sb);
Console.ReadKey();
}

Solution

I think you kind of reinventing the wheel a bit here. You could use the ValidationAttribute.

Since C# doesn't allow generics in Attribute classes you either have to create an attribute per type or use an enum to specific what type. I personally prefer an attribute per type.

An Example of use the ValidationAttrubte for DecimalParser

public class DecimalParserAttribute : ValidationAttribute
{
    public DecimalParserAttribute() : base("Cannot convert to decimal")
    {
    }

    public override bool IsValid(object value)
    {
        if (value == null)
        {
            return false;
        }

        var stringValue = Convert.ToString(value);

        decimal decimalResult;
        return decimal.TryParse(stringValue, out decimalResult);
    }
}


Now to perform the validation you need to use the Validator Class

var p = new Product() {NoOfItems = "1", GRodes = "4w", Weight = "5", WRodes = "2q3"};
var validationResults = new Collection();
if (!Validator.TryValidateObject(p, new ValidationContext(p), validationResults, true))
{
    // If we are here there was validation errors 
    var x = string.Join(Environment.NewLine,
        validationResults.SelectMany(r => r.MemberNames.Select(n => n + " " + r.ErrorMessage)));
}


This to me fits more in with what you are doing, validation, with the benefit of using the built in .Net Framework classes.

Code Snippets

public class DecimalParserAttribute : ValidationAttribute
{
    public DecimalParserAttribute() : base("Cannot convert to decimal")
    {
    }

    public override bool IsValid(object value)
    {
        if (value == null)
        {
            return false;
        }

        var stringValue = Convert.ToString(value);

        decimal decimalResult;
        return decimal.TryParse(stringValue, out decimalResult);
    }
}
var p = new Product() {NoOfItems = "1", GRodes = "4w", Weight = "5", WRodes = "2q3"};
var validationResults = new Collection<ValidationResult>();
if (!Validator.TryValidateObject(p, new ValidationContext(p), validationResults, true))
{
    // If we are here there was validation errors 
    var x = string.Join(Environment.NewLine,
        validationResults.SelectMany(r => r.MemberNames.Select(n => n + " " + r.ErrorMessage)));
}

Context

StackExchange Code Review Q#150278, answer score: 4

Revisions (0)

No revisions yet.