设置没有Setter的C#属性

设置没有Setter的C#属性,c#,reflection,C#,Reflection,在C#中,存在异常类。出于测试目的,我希望能够将其StackTrace属性设置为任意字符串StackTrace没有setter,因此我的第一次尝试是尝试使用反射: Exception instance = new Exception("Testing"); PropertyInfo propertyInfo = typeof(Exception).GetProperty("StackTrace"); propertyInfo.SetValue(instance, "Sample StackTra

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

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

System.ArgumentException:未找到属性集方法。


有没有办法设置
StackTrace
属性?一般来说,有没有办法设置缺少setter的属性?

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

您可以派生自己的异常类并重写
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;
}
被调用的方法是这样实现的:

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;
}
因此,如果您将字段
\u stackTraceString
设置为任何
字符串
,您将获得
\u stackTraceString
+
\u remoteStackTraceString

可以使用设置字段

我是用电脑得到这个信息的

不要在生产中这样做。事情的设计是有原因的,只是公开的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提出的解决方案。

您可以使用Reflector找出此属性调用的支持变量,然后使用reflection来设置。扩展您自己的异常类怎么样?@Nick-没有支持字段:
返回此。GetStackTrace(true)实际上有一个支持字段@Nick在is断言中是正确的:
\u stackTraceString
可通过反射进行设置。这是一个好的解决方案,但覆盖所有异常以使用自定义异常类是不可行的。也许您也可以编写一个包装异常类,仅用于测试目的。没错,在测试库中创建我自己的异常类(仅在该库内部)可能比反射更好。在
C
中,对变量名使用
\u paramName
是否正常。o@mmcrae这在私有字段中非常常见。但是,通过键入“\u paramName”你让它看起来像是在考虑参数名——这对那些人来说肯定不正常。我发布的代码将其用于私有字段,而不是参数。有些人使用
这个。
代替,如果使用
\u
则有理由将其用作后缀。