问题
I've never posted a question of this nature before, so if it's not proper for SO, just don't hurt my feelings too bad and I'll delete it.
In the interest of keeping everything I care about as close to the left margin as possible, I keep wishing I could write something like:
DataService1.DataEntities dataEntities = new(constructorArg1, ...)
I think another reason is I like the extra screen real estate I get by using var when the type is already present on the right side of the assignment, but my brain has too many years of looking for the type on the left side. Then again, being stuck in my ways isn't such a good reason to wish for a spec...
回答1:
Has the C# design committee ever considered this object creation syntax?
Yes, we have. We considered it a couple years ago. As evidence of this claim, see the last paragraph of my article here:
http://blogs.msdn.com/b/ericlippert/archive/2009/01/26/why-no-var-on-fields.aspx
The consensus of the design team was that this was a "nice to have" feature but not sufficiently compelling that it was worth the considerable cost of designing, implementing, testing, documenting and maintaining the feature.
I note also that the comments to the blog entry I linked to are very negative about the feature; it seemed like a lot of people found the syntax unattractive. That was also points against doing the feature.
However, the proposed syntax becomes particularly nice if you can combine it with other language features that promote the concise declaration of immutable types; if we do such a feature in a hypothetical future version of the language, then the syntax you propose becomes more compelling.
I note further that we in general resist features that require inference from "outside" to "inside"; we prefer that type information flow from the inside out. Consider for example this problem:
M(new(blah));
Suppose M has two overloads, one that takes a C, and one that takes a D. Is that "new C(blah)" or "new D(blah)"? It could be either. Now we have to analyze both! And if they both work then we have to figure out which is better.
It gets worse. Suppose you have
M(new(new(blah)));
where again M takes a C and a D, and C has two constructors that take an E or an F, and D has two constructors that take an G and an H. Which of:
M(new C(new E(blah)));
M(new C(new F(blah)));
M(new D(new G(blah)));
M(new D(new H(blah)));
is chosen, and why?
When you reason from outside to inside you quickly get into "combinatoric explosions" where the number of cases to analyze becomes O(cn) in the depth of the nesting.
C# does reason in this manner for lambdas and that is one of the hardest parts of the compiler to make performant and correct, believe me. We're not eager to add a similar feature to constructors. If we were to add this syntax it would probably be limited to scenarios in which the type was unambiguously known by analyzing the left hand side of a variable declaration or assignment expression.
(As always, I note that Eric's musings about hypothetical future language features in unannounced and entirely fictional products that do not have schedules or budgets is for entertainment purposes only, and not to be construed as a promise of any particular future product with any particular feature set.)
回答2:
It infers from the left side backwards to the expression. And if the expression is non trivial that gets ugly quite fast.
You can understand what an expression does by just looking at the expression itself almost always(except some lamda type inference), and that isn't possible with your syntax. With lamdas the gain is quite large, so the complicated inference is a good trade-off for lamdas, but adding that complexity for such a trivial feature is a bad trade-off for simple variable initialization.
You could special case "assignment to variable where the outmost expression on the right side is a new
expression." Sounds very inelegant to me. Especially since the var
feature already achieves something very similar, while being more flexible.
回答3:
If you want to create an object of the same type as the member used to store it without having to repeat the type name, you can use "Stockton new". The downside is that you have to repeat the member name in the initialization. Here's how it looks:
class Program
{
private static T New<T>(out T item) where T : new()
{
item = new T();
return item;
}
static Dictionary<Int32, Int32> _member = New(out _member);
static void Main(string[] args)
{
Dictionary<Int32, Int32> local = New(out local);
}
}
In addition, we can extend this method to create concrete classes for corresponding interfaces with a couple of simple overloads:
public static IDictionary<TKey, TValue> New<TKey, TValue>(out IDictionary<TKey, TValue> item)
{
item = new Dictionary<TKey, TValue>();
return item;
}
public static IList<T> New<T>(out IList<T> item)
{
item = new List<T>();
return item;
}
Now you can write this:
IDictionary<Int32, Int32> local = New(out local);
An abomination, a curiosity, or a useful technique? You decide.
回答4:
There is now a championed proposal and an implementation of this feature precisely. We are likely to see it in C# 8.0.
See https://github.com/dotnet/csharplang/blob/master/proposals/target-typed-new.md
回答5:
Not sure about that but if you are looking to keep things to the left, you could instead use:
var dataEntities = new DataService1.DataEntities(constructorArg1, ...)
回答6:
Also how about having:
DataType dt;
Mean the same as:
DataType dt = new DataType();
And then:
DataType dt = { ParamOne = 1, ParamTwo = 2 };
Is the same as:
DataType dt = new DataType(){ ParamOne = 1, ParamTwo =2 };
来源:https://stackoverflow.com/questions/5780648/has-the-c-sharp-spec-team-committee-ever-considered-this-object-creation-syn