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

Viewed 436

Initializing a class like this:

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

I am getting an InvalidCastException on one of the assignments. 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. Maybe there is a more fine-grained debug step I can use?

3 Answers

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.

What I've found in similar situations is that if Visual Studio can be made to break at the moment the InvalidCastException occurs i.e. on that specific line then the Call Stack and local variables are much more immediate and useful.

Unfortunately, 'break when thrown' is suppressed by Visual Studio default settings for many exception types. 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:

Default Exception Settings

to this:

enter image description here

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. In your settings under Options -> Debugging -> General, uncheck Step over properties and operators. Then set a break point at your initializer and step through it with 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'. in 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. 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:

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:

Result in the console

Related