toddmo toddmo - 3 months ago 14
Vb.net Question

vb.net vs c# object initializer: limitation in c#?

In VB.NET you can use an object initializer and reference the same members on the right hand side, like this:

GetValue.Add(New ArrayIndexInfo() With {
.Type = CType(NvpInfo(Index), Type),
.Name = NvpInfo(Index + 2).ToString,
.NvpValues = CType(.Type.GetField(NvpInfo(Index + 1).ToString).GetValue(Instances.First(Function(o) o IsNot Nothing AndAlso o.GetType = CType(NvpInfo(Index), Type))), NameValuePair())
})


Notice how in the line that sets
.NvpValues
you can reference
.Type
and that it's no problem.

But if you try to do that in c# (or like I did, try to convert a project from vb.net to c#), you get an error.


<variable> is not declared


I worked around it like this, which is not DRY because
((Type)NvpInfo[Index])
is repeated:

functionReturnValue.Add(new ArrayIndexInfo {
Type = (Type)NvpInfo[Index],
Name = NvpInfo[Index + 2].ToString(),
NvpValues = (NameValuePair[])((Type)NvpInfo[Index]).GetField(NvpInfo[Index + 1].ToString()).GetValue(Instances.First(o => o != null && o.GetType() == (Type)NvpInfo[Index]))
});



  1. Why doesn't c# allow this? I think it should. I think converting legacy code to c# should be as painless as possible.

  2. Is there a better way that I get around this and still use the object initializer?


Answer

To answer the question, I'll base myself on a simplified version of your example

VB.NET:

Dim c = New SomeClass With {
    .Prop1 = "abc",
    .Prop2 = .Prop1
}

Console.WriteLine(c.Prop1) 'prints "abc"
Console.WriteLine(c.Prop2) 'prints "abc"

C#

var c = new SomeClass
{
    Prop1 = "abc",
    Prop2 = Prop1 // won't compile. Can't reference Prop1 here.
};

Console.WriteLine(c.Prop1);
Console.WriteLine(c.Prop2);

Addressing your last question:

Is there a better way that I get around this and still use the object initializer?

So one of your concerns is that because C# doesn't allow referencing other properties in an object initialization statement, that it causes you to violate the DRY principle. But really, all you need to do is use variables:

Working C# example that doesn't violate DRY principle:

string temp = "abc";
var c = new SomeClass
{
    Prop1 = temp,
    Prop2 = temp
};

Console.WriteLine(c.Prop1); // prints "abc"
Console.WriteLine(c.Prop2); // prints "abc"

Why doesn't c# allow this? I think it should.

Obviously, only the designers of the language can truly answer that one. But I can at least share why I like C#'s design decision better. For instance, in the VB.NET version, if I mistakenly initialize the properties in a different order:

Dim c = New SomeClass With {
    .Prop2 = .Prop1,
    .Prop1 = "abc"
}

Console.WriteLine(c.Prop1) 'prints "abc"
Console.WriteLine(c.Prop2) 'prints nothing

... the code is still "legal" but I've now inadvertently introduced a bug, and Prop2 is now initialized incorrectly.

Because C# disallows this, it prevents most bugs related to the order of property initialization. I agree that in this very simplified example it's hard to imagine anyone falling for that mistake. But with more properties and more complicated initialization statements, it may not be so obvious, and mistakes can more easily be made. C# helps you avoid these subtle bugs.

I think converting legacy code to c# should be as painless as possible.

I guess you're implying that VB.NET is a legacy language? Some may take offense :)

But more seriously, are you implying that language design decisions should be made to facilitate migration from other languages? C# and VB.NET are two full featured languages in their own right. They are not meant to have matching and symmetrical language designs. If they did, what would be the point of having 2 separate languages?

No. They are 2 different languages with 2 different philosophies. We should consider ourselves lucky that the migration path is as easy as it is currently. There is no reason why it needs to be.