设置没有Setter的c#属性



在c#中有Exception类。出于测试的目的,我希望能够将其StackTrace属性设置为任意字符串。StackTrace没有setter,所以我的第一次尝试是尝试使用反射:

Exception instance = new Exception("Testing");
PropertyInfo propertyInfo = typeof(Exception).GetProperty("StackTrace");
propertyInfo.SetValue(instance, "Sample StackTrace value", null);
这将产生运行时错误:

System.ArgumentException : Property set method not found.

是否有任何方法可以设置StackTrace属性?更一般地说,有没有一种方法可以设置一个没有setter的属性?

您可以派生自己的异常类并覆盖StackTrace属性,该属性是虚拟的:

public sealed class MyException: Exception
{
    public MyException(string message, string stackTrace): base(message)
    {
        _stackTrace = stackTrace;
    }
    public override string StackTrace
    {
        get
        {
            return _stackTrace;
        }
    }
    private readonly string _stackTrace;
}

请注意,要正确地做到这一点,您应该真正实现所有标准的异常构造函数,但对于单元测试,这可能不是严格必要的。

参见设计自定义异常了解更多细节:

这个属性是这样实现的:

public virtual string StackTrace
{
    [__DynamicallyInvokable, TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
    get
    {
        return this.GetStackTrace(true);
    }
}

被调用的方法是这样实现的:

private string GetStackTrace(bool needFileInfo)
{
    string text = this._stackTraceString;
    string text2 = this._remoteStackTraceString;
    if (!needFileInfo)
    {
        text = this.StripFileInfo(text, false);
        text2 = this.StripFileInfo(text2, true);
    }
    if (text != null)
    {
        return text2 + text;
    }
    if (this._stackTrace == null)
    {
        return text2;
    }
    string stackTrace = Environment.GetStackTrace(this, needFileInfo);
    return text2 + stackTrace;
}

因此,如果您将字段_stackTraceString设置为任何String,您将得到_stackTraceString + _remoteStackTraceString

您可以使用FieldInfo.SetValue设置字段。

我通过http://ilspy.net得到了这个信息。

不要在生产环境中这样做。事物以特定的方式设计是有原因的,只是暴露的API是有保证的,一个小的升级可能会改变这个内部实现细节并破坏你的代码,所以永远不要依赖内部细节,只暴露的API。

欢呼。

您可以修改对象的后备字段:

Exception instance = new Exception("Testing");
var f = typeof(Exception).GetField("_stackTraceString", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.SetField);
f.SetValue(instance, "hello");

这应该可以工作,要获得私有字段列表,您可以使用:

var fields = typeof(Exception).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);

我个人更喜欢Matthew Watson提出的解决方案。

Exception对象的StackTrace属性是在堆栈遍历期间由运行时设置的,因此我们不能手动设置。

相关内容

  • 没有找到相关文章

最新更新