2
\$\begingroup\$

I have a 'speed problem' with a program I'm currently developing. I already have encountered the methods which costs some time.

public void ConvertDataFrameToValueFields()
    {
        List<byte[]> items = new List<byte[]>() { new byte[2], new byte[2], new byte[2], new byte[2] };

        items[0][0] = this.DataBytes[0];
        items[0][1] = this.DataBytes[1];
        items[1][0] = this.DataBytes[2];
        items[1][1] = this.DataBytes[3];
        items[2][0] = this.DataBytes[4];
        items[2][1] = this.DataBytes[5];
        items[3][0] = this.DataBytes[6];
        items[3][1] = this.DataBytes[7];

        int i = 0;
        IEnumerable<PropertyInfo> result = this.determineCanMessageValueFields();

        foreach (var prop in result)
        {
            if (prop.PropertyType == typeof(MessageStatusValueField))
            {
                prop.SetValue(this, new MessageStatusValueField(BitConverter.ToUInt16(items[i], 0), prop.Name, this.UnitType), null);
            }
            else if (prop.PropertyType == typeof(MessageValueField))
            {
                prop.SetValue(this, new MessageValueField(BitConverter.ToUInt16(items[i], 0), prop.Name), null);
            }
            else if (prop.PropertyType == typeof(MessageValueFieldInt32))
            {
                prop.SetValue(this, new MessageValueFieldInt32(BitConverter.ToUInt16(items[i], 0), prop.Name), null);
            }
            else if (prop.PropertyType.GetCustomAttributes(false).Count(x => x.GetType() == typeof(BitmaskValueFieldClass)) > 0)
            {
                var tempField = new MessageValueField(BitConverter.ToUInt16(items[i], 0), prop.Name);
                prop.SetValue(this, Convert.ChangeType(tempField, prop.PropertyType), null);
            }
            i++;
        }
    }




     private IEnumerable<PropertyInfo> determineCanMessageValueFields()
            {
                //Get all properties with the 
                //custom attribute [IsValueField]
                return this.GetType().GetProperties()
                                     .Where(p => p.GetCustomAttributes(false)
                                     .Count(x => x.GetType() == typeof(IsValueField)) > 0)
                                     .OrderBy(x => ((IsValueField)x.GetCustomAttributes(false)[0]).ValueFieldIndex);
            }

 public object ToType(Type conversionType, IFormatProvider provider)
        {
            //...only convert if the conversion type is a BitmaskValueFieldClass
            if (conversionType.GetCustomAttributes(false).Count(x => x.GetType() == typeof(BitmaskValueFieldClass)) == 0)
            {
                throw new NotImplementedException("The conversion is only available for conversion types with the BitmaskValueFieldClass attribute");
            }

            //...create an instance of the conversion type
            var instance = Activator.CreateInstance(conversionType);

            //...go thru each property and set the value
            foreach (var item in instance.GetType().BaseType.GetProperties())
            {
                item.SetValue(instance, this.GetType().GetProperty(item.Name).GetValue(this, null), null);
            }

            return instance;
        }

The method ConvertDataFrameToValueFields() is the sticking point. I know it is because of the prop.SetValue() and the ToType() IConvertible method calls. When I am removing the ConvertDataFrameToValueFields() method I gain the missing time I need to fulfill the project.

Is there a way to improve the whole thing? Problem is that the idea has to be as it is. In the ConvertDataFrameToValueFields() method I have to map the returning DataFrame, the DataBytes array, to the MessageValueField properties of the specific class. I'm getting all containing messagevaluefields by calling the ConvertDataFrameToValueFields().

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Why is speed a problem? Are you calling these methods on the same type many times? If that's the case, you might benefit from using reflection once to generate code for that type and then use that generated code repeatedly. \$\endgroup\$
    – svick
    May 7, 2014 at 18:01
  • \$\begingroup\$ I also wonder what those property setters are doing. If they're not simple value settings, then perhaps the problem is not that your code is slow but that the setters it's invoking are slow. Removing the whole method would not distinguish between those cases. \$\endgroup\$
    – breischl
    May 8, 2014 at 21:14
  • 1
    \$\begingroup\$ could you post a working sample? may we analyse the root cause. \$\endgroup\$
    – pushpraj
    Jul 14, 2014 at 5:39

1 Answer 1

2
\$\begingroup\$

Style

Based on the naming guidlines method names should use PascalCasing casing.

determineCanMessageValueFields()

Instead of calling Count() and checking if it is greater than 0 you should call Any().

So determineCanMessageValueFields() would become

private IEnumerable<PropertyInfo> determineCanMessageValueFields()
{
    return this.GetType().GetProperties()
                            .Where
                                (p => p.GetCustomAttributes(false)
                                            .Any(x => x.GetType() == typeof(IsValueField))
                                )
                            .OrderBy(x => ((IsValueField)x.GetCustomAttributes(false)[0]).ValueFieldIndex);
}

ConvertDataFrameToValueFields()

The creation of the List<byte[]> is not needed at all. If you increment the i counter by 2 you can just use this.DataBytes for the calling BitConverter.ToUInt16(this.DataBytes,i).

This leads after using Any()instead of Count() > 0 to

public void ConvertDataFrameToValueFields()
{

    int i = 0;

    foreach (var prop in DetermineCanMessageValueFields())
    {
        ushort value = BitConverter.ToUInt16(this.DataBytes, i);

        if (prop.PropertyType == typeof(MessageStatusValueField))
        {
            prop.SetValue(this, new MessageStatusValueField(value, prop.Name, this.UnitType), null);
        }
        else if (prop.PropertyType == typeof(MessageValueField))
        {
            prop.SetValue(this, new MessageValueField(value, prop.Name), null);
        }
        else if (prop.PropertyType == typeof(MessageValueFieldInt32))
        {
            prop.SetValue(this, new MessageValueFieldInt32(value, prop.Name), null);
        }
        else if (prop.PropertyType.GetCustomAttributes(false).Any(x => x.GetType() == typeof(BitmaskValueFieldClass)))
        {
            var tempField = new MessageValueField(value, prop.Name);
            prop.SetValue(this, Convert.ChangeType(tempField, prop.PropertyType), null);
        }

        i += 2;
    }
}

and applying the Any() change to the ToType() method

public object ToType(Type conversionType, IFormatProvider provider)
{

    if (!conversionType.GetCustomAttributes(false).Any(x => x.GetType() == typeof(BitmaskValueFieldClass)))
    {
        throw new NotImplementedException("The conversion is only available for conversion types with the BitmaskValueFieldClass attribute");
    }

    var instance = Activator.CreateInstance(conversionType);

    foreach (var item in instance.GetType().BaseType.GetProperties())
    {
        item.SetValue(instance, this.GetType().GetProperty(item.Name).GetValue(this, null), null);
    }

    return instance;
}  

Comments

Comments should be used to explain why something is done, not what is done. The what part should be done by the code itself.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.