开发者

c# parameter performance

So I have a to call a method quite regularly as part of a pattern. It looks like something like this:

DoWork(new TimeSpan(0, 0, 2, 0));

Or in another part of the code:

DoWork(new TimeSpan(0, 0, 6, 50));

In each case the parameter never changes and I recently woke up and worked out what a performance whack it is to keep creating the parameter for every call. The solution I have is this:

// instance field
TimeSpan _cachedValue = new TimeSpan(0, 0, 2, 0);
// and when called, 
DoWork(this._cachedValue)

This is all pretty obvious, the issue I have with it though is storing the parameter value in a field... its messy - in an already bloated class (In one class for example I'd call the do work method with 10 or so variants many thousands of times each - so thats ten extra fields).

It would be cool however if I could do something like this:

DoWork([DoesNotChange()]new TimeSpan(0, 0, 2, 0));

This theoretical attrib开发者_StackOverflow社区ute on the parameter would indicate that for that particular call the value only ever needs to be worked out once, and then passed to method repeatedly.

So is anything like this possible? Or am I just off my nut?

Cheers

EDIT:

Wow you folks work fast, thanks. As for my question, I should of learnt last time not to over simplify - sorry. I'm going to post an actual code snippet for clarity. This class is used for databinding in a Silverlight app. I'm using strong typing for PropertyChanged events for maintainability:

internal class BasicDataClass : INotifyPropertyChanged
{
    private readonly Expression<Func<double>> _propertySelector;
    private double _someFieldA;
    private double _someFieldB;
    private double _someFieldC;

    public BasicDataClass()
    {
        _propertySelector = () => SomeFieldC;
    }

    /// <summary>
    /// This is fastest
    /// </summary>
    public double SomeFieldA
    {
        get { return _someFieldA; }
        set
        {
            if (!_someFieldA.Equals(value))
            {
                _someFieldA = value;
                PropertyChanged.Raise(this, "SomeFieldA");
            }
        }
    }

    /// <summary>
    /// This is many times slower
    /// </summary>
    public double SomeFieldB
    {
        get { return _someFieldB; }
        set
        {
            if (!_someFieldB.Equals(value))
            {
                _someFieldB = value;
                PropertyChanged.Raise(() => SomeFieldB);
            }
        }
    }

    /// <summary>
    /// This is only, very slightly slower than A
    /// but requires an extra field
    /// </summary>
    public double SomeFieldC
    {
        get { return _someFieldC; }
        set
        {
            if (!_someFieldC.Equals(value))
            {
                _someFieldC = value;
                PropertyChanged.Raise(_propertySelector);
            }
        }
    }

    #region INotifyPropertyChanged Members

    /// <summary>
    /// The property changed.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

And for reference, the Raise extension methods:

    public static void Raise<TValue>(
        this PropertyChangedEventHandler handler, Expression<Func<TValue>> propertySelector)
    {
        if (handler != null)
        {
            var memberExpression = propertySelector.Body as MemberExpression;
            if (memberExpression != null)
            {
                object sender = ((ConstantExpression)memberExpression.Expression).Value;
                handler(sender, new PropertyChangedEventArgs(memberExpression.Member.Name));
            }
        }
    }

    public static void Raise(this PropertyChangedEventHandler handler, object sender, string propertyName)
    {
        if (handler != null)
        {
                handler(sender, new PropertyChangedEventArgs(propertyName));
        }
    }

Again, sorry for not being specific.


These are basically constants, right? So why not populate static fields with them:

private static readonly TimeSpan RpcTimeOut = TimeSpan.FromSeconds(2);

...
DoWork(RpcTimeOut);

I think that's cleaner than trying to attribute the parameter.

By having these as static fields, you wouldn't really be bloating any objects - there'd only be one value for the field per AppDomain.


You could pull these out into a configuration file - that way you can change them if you need to and the calls to read the configuration (using System.Configuration) are cached after the first read.


If you want a variable "worked out" (I'm assuming you mean assigned a value?), use a constant TimeSpan.


Practically. If you're going to do the instance field thing, you might as well make the variables static readonly members:

static readonly TimeSpan t = new TimeSpan(0, 0, 2, 0);

By doing it like this instead of constructing the TimeSpans inline you also have the opportunity to give the variables a descriptive name.

Theoretically. I don't think your suggestion of using some kind of inline attribute or directive will work in practice, although the CLR theoretically supports it. You'd have to convince the compiler to apply 'constant folding' to your new TimeSpan(), and I don't know of a way to force that.

EDIT: Constant Folding is a technique a compiler employs to reduce an expression consisting of constants into a single constant. That way the expression does not have to be evaluated at runtime. Theoretically a struct can be a constant, and the TimeSpan constructor is deterministic, so constant folding is possible. but even TimeSpan.MaxValue is not initialized in that way[1].

[1] I checked that using the Reflector tool.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜