设置没有Setter的C#属性

时间:2014-03-14 12:38:17

标签: c# reflection

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

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的属性?

4 个答案:

答案 0 :(得分:10)

您可以派生自己的异常类并覆盖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;
}

请注意,要正确执行此操作,您应该真正实现所有标准异常构造函数,但对于单元测试,这可能不是绝对必要的。

有关详细信息,请参阅Designing Custom Exceptions

答案 1 :(得分:2)

该属性以这种方式实现:

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。

干杯。

答案 2 :(得分:1)

您可以修改对象的支持字段:

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提出的解决方案。

答案 3 :(得分:0)

Exception对象的StackTrace属性由堆栈遍历期间的运行时设置,因此我们无法手动设置它。