c#参数性能

c#参数性能,c#,parameters,C#,Parameters,因此,作为模式的一部分,我必须定期调用一个方法。它看起来像这样: DoWork(new TimeSpan(0, 0, 2, 0)); DoWork([DoesNotChange()]new TimeSpan(0, 0, 2, 0)); 或在代码的另一部分中: DoWork(new TimeSpan(0, 0, 6, 50)); 在每一种情况下,参数都不会改变,我最近醒来发现,为每次调用持续创建参数会对性能造成多大的影响。我的解决方案是: // instance field TimeSpan

因此,作为模式的一部分,我必须定期调用一个方法。它看起来像这样:

DoWork(new TimeSpan(0, 0, 2, 0));
DoWork([DoesNotChange()]new TimeSpan(0, 0, 2, 0));
或在代码的另一部分中:

DoWork(new TimeSpan(0, 0, 6, 50));
在每一种情况下,参数都不会改变,我最近醒来发现,为每次调用持续创建参数会对性能造成多大的影响。我的解决方案是:

// instance field
TimeSpan _cachedValue = new TimeSpan(0, 0, 2, 0);
// and when called, 
DoWork(this._cachedValue)
这是非常明显的,但我的问题是将参数值存储在字段中。。。它很凌乱——在一个已经臃肿的类中(例如,在一个类中,我用10个左右的变量调用do work方法,每个变量调用了数千次——因此这是10个额外的字段)

不过,如果我能做这样的事情,那就太酷了:

DoWork(new TimeSpan(0, 0, 2, 0));
DoWork([DoesNotChange()]new TimeSpan(0, 0, 2, 0));
参数上的这个理论属性表明,对于那个特定的调用,值只需要计算一次,然后反复传递给方法

那么这样的事情可能发生吗?还是我疯了

干杯

编辑:

哇,你们工作很快,谢谢。 至于我的问题,上次我应该学会不要过分简化——对不起。为了清晰起见,我将发布一个实际的代码片段。此类用于Silverlight应用程序中的数据绑定。为了可维护性,我对PropertyChanged事件使用强类型:

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
}
内部类BasicDataClass:INotifyPropertyChanged
{
私有只读表达式_propertySelector;
私人双人房(someFieldA);;
私人双人房b;
私人双_someFieldC;
公共类()
{
_propertySelector=()=>SomeFieldC;
}
/// 
///这是最快的
/// 
公共双萨默菲尔德酒店
{
获取{return\u someFieldA;}
设置
{
如果(!\u someFieldA.Equals(value))
{
_someFieldA=值;
财产变更。提高(这是“SomeFieldA”);
}
}
}
/// 
///这要慢很多倍
/// 
公共双字段B
{
获取{return\u someFieldB;}
设置
{
如果(!\u someFieldB.Equals(value))
{
_someFieldB=值;
PropertyChanged.Raise(()=>SomeFieldB);
}
}
}
/// 
///这只是,非常稍微慢一点
///但是需要一个额外的字段
/// 
公共领域
{
获取{return\u someFieldC;}
设置
{
如果(!\u someFieldC.等于(值))
{
_someFieldC=值;
PropertyChanged.Raise(_propertySelector);
}
}
}
#区域INotifyProperty更改成员
/// 
///财产发生了变化。
/// 
公共事件属性更改事件处理程序属性更改;
#端区
}
作为参考,Raise扩展方法:

    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));
        }
    }
publicstaticvoidraise(
此PropertyChangedEventHandler处理程序、表达式propertySelector)
{
if(处理程序!=null)
{
var memberExpression=propertySelector.Body作为memberExpression;
if(memberExpression!=null)
{
对象发送者=((ConstantExpression)memberExpression.Expression).Value;
处理程序(发送方,新属性changedeventargs(memberExpression.Member.Name));
}
}
}
公共静态void提升(此PropertyChangedEventHandler处理程序、对象发送器、字符串propertyName)
{
if(处理程序!=null)
{
处理程序(发送方,新PropertyChangedEventArgs(propertyName));
}
}

同样,很抱歉没有具体说明。

您可以将它们拉到配置文件中,这样您就可以在需要时更改它们,并且读取配置的调用(使用System.configuration)在第一次读取后被缓存。

这些基本上都是常量,对吗?那么,为什么不用它们填充静态字段呢

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

...
DoWork(RpcTimeOut);
我认为这比试图对参数进行属性化更清晰


通过将这些字段作为静态字段,您实际上不会使任何对象膨胀-每个AppDomain的字段只有一个值。

如果您想“计算”变量(我假设您的意思是指定一个值?),请实际使用恒定的时间跨度。

如果要执行“实例字段”操作,不妨将变量设置为静态只读成员:

static readonly TimeSpan t = new TimeSpan(0, 0, 2, 0);
通过这样做而不是内联构造TimeSpans,您还可以为变量提供一个描述性名称

理论上。 我认为您建议使用某种内联属性或指令在实践中行不通,尽管CLR理论上支持它。您必须说服编译器将“常量折叠”应用于您的
新TimeSpan()
,我不知道有什么方法可以强制这样做

编辑:常量折叠是编译器用来将由常量组成的表达式缩减为单个常量的一种技术。这样就不必在运行时计算表达式。理论上,
struct
可以是常数,
TimeSpan
构造函数是确定性的,因此常数折叠是可能的。但是,即使TimeSpan.MaxValue也不是以这种方式初始化的[1]


[1] 我使用Reflector工具检查了这一点。

值类型无论如何都不能更改,它们的值是被复制的。为了使它更加优雅,静态时间跨度可以位于单独的、名为“Common”或“Data”的静态类中,然后整个项目中的任何类都可以有:DoWork(Common.TwoSeconds);是的,它们是常量。。。我可以修改扩展方法以接受存储在静态字段中的表达式(请参见编辑)。我的问题更多的是关于在课堂上减少混乱/整齐地编码。“不断折叠”听起来最像我问这个问题时的意思——可惜它不起作用