简体   繁体   English

是否可以按成员调试结构/类初始化成员?

[英]Is it possible to debug a struct/class initialization member by member?

Initializing a class like this:像这样初始化 class :

var x = new Item()
{
 ID = (int)...,
 Name = (string)...,
 ..
};

I am getting an InvalidCastException on one of the assignments.我在其中一项作业中收到 InvalidCastException。 There are quite a lot of them and the exception occurs on the whole expression even if I run the debugger line-by-line.它们有很多,即使我逐行运行调试器,整个表达式也会出现异常。 The exception doesn't give any clue either what it's trying to cast to what.该异常并没有给出任何线索,也没有给出它试图投射到什么的任何线索。

Is there a way to debug each assignment individually?有没有办法单独调试每个作业? I've seen the debugger separately stops 3 times on expressions like foreach(x in y) so it seems a little strange it isn't doing that here, and detracts from the attraction of using this handy initialization syntax.我已经看到调试器在foreach(x in y)之类的表达式上分别停止了 3 次,所以在这里没有这样做似乎有点奇怪,并且降低了使用这种方便的初始化语法的吸引力。 Maybe there is a more fine-grained debug step I can use?也许我可以使用更细粒度的调试步骤?

Your question is "Is it possible to debug a struct/class initialization member by member?".您的问题是“是否可以按成员调试结构/类初始化成员?”。

So, up front, I'm not directly answering that question as worded because when I carefully read the body of your post it sounds like the essential question is how to identify the 'smoking line' root cause of this InvalidCastException right when it happens.所以,在前面,我没有直接回答这个问题的措辞,因为当我仔细阅读你的帖子的正文时,听起来基本问题是如何在这个 InvalidCastException 发生时识别“吸烟线”的根本原因。

What I've found in similar situations is that if Visual Studio can be made to break at the moment the InvalidCastException occurs ie on that specific line then the Call Stack and local variables are much more immediate and useful.我在类似情况下发现的是,如果可以在 InvalidCastException 发生的那一刻(即在该特定行上)中断 Visual Studio,那么调用堆栈和局部变量会更加直接和有用。

Unfortunately, 'break when thrown' is suppressed by Visual Studio default settings for many exception types.不幸的是,许多异常类型的 Visual Studio 默认设置抑制了“抛出时中断”。 But it's very easy to turn on 'break when thrown' for ALL exceptions.但是很容易为所有异常打开“抛出时中断”。 Just change this default setting in the Exceptions window in Visual Studio from this:只需在 Visual Studio 的 Exceptions window 中更改此默认设置:

默认例外设置

to this:对此:

在此处输入图像描述

This doesn't "always" help but it's a good start.这并不“总是”有帮助,但它是一个好的开始。 It's so easy why not try that first to see if rapid resolution is possible.这很容易,为什么不先尝试一下,看看是否可以快速解决。 Hope this turns out to be useful in your case.希望这对您的情况有用。

Not sure if this is an option in VS 2017, I only have 2019 at hand.不确定这是否是 VS 2017 中的一个选项,我手头只有 2019 年。 In your settings under Options -> Debugging -> General , uncheck Step over properties and operators .Options -> Debugging -> General下的设置中,取消选中Step over properties and operator Then set a break point at your initializer and step through it with F11 (Step-Into).然后在初始化程序处设置一个断点并使用 F11(Step-Into)单步执行。 You will hit each property setter until the exception is thrown.您将点击每个属性设置器,直到抛出异常。

Please excuse me if I am missing something (will delete if thats the case) but using an invalid cast like this:如果我遗漏了某些东西(如果是这种情况,将删除)但使用这样的无效演员表,请原谅:

struct Item
{
    public int ID { get; set; }
    public Derived Derived { get; set; }
}
public class Base
{
    public string Name { get; set; }
}
public class Derived : Base
{
    public string AdditionalProperty { get; set; }
}
var baseClass = new Base()
{
    Name = "foo",
};
try
{
    var x = new Item()
    {
          ID = (int)20,
          Derived = (Derived)baseClass,
    };
}
catch(Exception e)
{
          Console.WriteLine(e.Message);
}

neatly catches the error like this Unable to cast object of type 'Base' to type 'Derived'.巧妙地捕捉到这样的错误Unable to cast object of type 'Base' to type 'Derived'. in vs2017在vs2017中

However this breaks on the first error, we might wanna initalize an object this way and log all cast errors withouth exiting the initialisation.但是,这会在第一个错误时中断,我们可能想以这种方式初始化 object 并在不退出初始化的情况下记录所有转换错误。 We can do this by implementing our own casting for this sample:我们可以通过为此示例实现我们自己的转换来做到这一点:

public static T TryCast<T>(Object _object)
        {
            try
            {
                return (T)_object;
            }
            catch (Exception e)
            {
                Console.WriteLine($"Cant cast object of type {_object.GetType().ToString()} to object of type {typeof(T)}");
            }
            return default(T);
        }
 public static T TryCast<T>(IConvertible _object)
        {
            try
            {
                return (T)Convert.ChangeType(_object, typeof(T));
            }
            catch (Exception e)
            {
                Console.WriteLine($"Cant convert object of type {_object.ToString()} to object of type {typeof(T)}");
            }
            return default(T);
        }

New types for demonstrating purposes用于演示目的的新类型

struct Item
    {
        public int ID { get; set; }
        public double FooDouble { get; set; }
        public Base Base { get; set; }
        public Derived Derived { get; set; }
        public string Bar { get; set; }
    }
    public class Base
    {
        public string Name { get; set; }
    }
    public class Derived : Base
    {
        public string AdditionalProperty { get; set; }
    }

We can then initalize our object like this:然后我们可以像这样初始化我们的 object:

var derived = new Derived()
            {
                Name = "DerivedFoo",
                AdditionalProperty = "Bar"
            };
            var _base = new Base()
            {
                Name = "BaseFoo"
            };
            var x = new Item()
            {
                ID = Utils.TryCast<int>("please no"),
                FooDouble = Utils.TryCast<double>(2),
                Base = Utils.TryCast<Base>(derived),
                Derived = Utils.TryCast<Derived>(_base),
                Bar = "Foo"
            };

And we neatly log any errors that might occur when casting:我们巧妙地记录了投射时可能发生的任何错误:

结果在控制台

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM