Replies: 29 comments
-
class C<T> { public C<U>() {} } How would you instantiate such class? |
Beta Was this translation helpful? Give feedback.
-
How would you differentiate between |
Beta Was this translation helpful? Give feedback.
-
@alrz very good question. public class MyClass<T>
public MyClass<U>()
{
}
}
// Explicit call requires some new syntax required (ugly):
var myInstance = new MyClass<int><string>("MyTest");
// little bit better.
var myInstance = new<string> MyClass<int>("MyTest");
// Implicit form works good.
var myInstance = new MyClass<int>("TEst"); |
Beta Was this translation helpful? Give feedback.
-
Compiler should disallow parameter-less generic form of constructor. |
Beta Was this translation helpful? Give feedback.
-
Could you supply an example of how this would be used, as at first glance, it seems a pointless feature? |
Beta Was this translation helpful? Give feedback.
-
It can be implemented just as C# syntax sugar. public class MyClass
{
// Currently it's impossible.
public MyClass<T>(T myParam)
{
// Constructor content
}
}
// Translates by Compiler to
public class MyClass
{
private MyClass()
{
}
[Constructor]
public static MyClass __constructor<T>(T myParams)
{
var instance = new MyClass()
instance.__constructorBody(myParams);
}
private void __constructorBody<T>(T myParam)
{
// Constructor content.
}
}
|
Beta Was this translation helpful? Give feedback.
-
Sorry, I'm not sure my question was very clear. I'm not so worried about how it could be implemented, more what would you use it for? As |
Beta Was this translation helpful? Give feedback.
-
@DavidArno for example if you want to allow to build object from Func or Action with variable parameters. public MyClass
{
public MyClass<T>(Func<T, Task> func)
{
}
public MyClass<T1, T2>(Func<T1, T2, Task> func)
{
}
public MyClass<T1, T2, T3>(Func<T1, T2, T3, Task> func)
{
}
} I am writing DI container, and there are many places where it can be useful. It's not hard to workaround, but this feature can make things simpler. // My current approach
public class MyClass
{
private MyClass()
{
}
public static MyClass Create<T>(Func<T, Task> func)
{
var instance = new MyClass();
instance.Init(func)
return instance;
}
private void Init<T>(Func<T, Task> func)
{
//Actual construction.
}
public static MyClass Create<T1, T2>(Func<T1, T2, Task> func)
{
var instance = new MyClass();
instance.Init(func)
return instance;
}
private void Init<T1, T2>(Func<T1, T2, Task> func)
{
//Actual construction
}
} |
Beta Was this translation helpful? Give feedback.
-
I updated topic with more convenient explicit construction syntax. But for constructors inplace of Invoke we can use "New" method name convention. |
Beta Was this translation helpful? Give feedback.
-
OK, I get what you are aiming at now (though I'm still intrigued as to what How about an alternative, where constructors can specify a default type for one or more of the type parameters, removing the need to specify them when creating an instance?: public MyClass<T1,T2,T3>
{
private readonly Func<T1, T2, T3, Task> _func;
public MyClass<T1, Unit, Unit>(Func<T1, Task> func) => _func = (x, _, _) => func(x);
public MyClass<T1, T2, Unit>(Func<T1, T2, Task> func) => _func = (x, y, _) => func(x, y);
public MyClass<T1, T2, T3>(Func<T1, T2, T3, Task> func) => _func = func;
}
var a = new MyClass<int>(async x =>...);
var b = new MyClass<int, int>(async (x, y) =>...);
var c = new MyClass<int, int, int>(async (x, y, z) =>...); |
Beta Was this translation helpful? Give feedback.
-
I actually quite like this idea, have briefly considered it a few times before myself. Regarding your question about what class Foo
{
private readonly int id;
public Foo<T>(T item, Func<T, int> itemIdFuncServiceThing)
{
this.id = itemIdFuncServiceThing(item);
}
} Obviously this is a silly simple toy example, but I've definitely made generic factories for non-generic types before, this is basically just tidying up the factory syntax. Another (slightly strange) scenario I hit fairly recently was an object that did some internal reflection work and only needed an instance of Type. Imagine something like this: class ReflectionWrapper
{
// This type should always implement ISomeRequiredInterface
private readonly Type type;
public ReflectionWrapper<T>()
where T: ISomeRequiredInterface
{
this.type = typeof(T);
}
} The implementation I have right now has a private constructor that takes a Type and a public static |
Beta Was this translation helpful? Give feedback.
-
Constructors aren't normal methods. I doubt that the CLR offers support for generic constructors at the time being. And I still completely don't get the use case. It seems completely esoteric. If you're trying to write something like factory bindings for a container there are plenty of syntactic options available to you which are succinct and allow the compiler to infer the generic type arguments. |
Beta Was this translation helpful? Give feedback.
-
Isn't this the same as:
What's the exact advantage of your code then? |
Beta Was this translation helpful? Give feedback.
-
// This base class is required to uniform access to MyClass<T> family.
public class MyClass
{
public abstract List<MyInfo> SomeDataFromGenericArguments {get;}
}
public class MyClass<T>: MyClass
{
// Currently that's possible.
public MyClass(T myParam)
{
}
} That's all about simplicity, like many other C# proposals. |
Beta Was this translation helpful? Give feedback.
-
@dmitriyse so it could be a simple compiler solution not touching the clr? My two examples would be interchangeable then. Is that something that would make sense to you? I just don't really see the true value of it. But I see why you'd prefer it. |
Beta Was this translation helpful? Give feedback.
-
class SomeClass
{
public static SomeClass Create<T>(T whatever)
{
// ...
}
} This is already a pretty common pattern. What if the compiler just gave us some by-convention syntax sugar and let us call these functions with the constructor syntax? And optionally it could go the other way as well and let you write them like constructors and have it output the That would nicely maintain full compatibility with the other languages, work with existing libraries, and be pretty lightweight to implement. It wouldn't have to be only generic methods either, any static method called We already have the Create pattern and it works fine, but when you think about it it is usually a workaround for something that constructors lack rather than a decision made for API niceness. I can see this making the language feel slightly more cohesive. |
Beta Was this translation helpful? Give feedback.
-
I agree with your suggestion. But pay attention to "this". class SomeClass
{
public static SomeClass Create<T>(T whatever)
{
// Where my lovely "this."
}
} Please see this comment #266 (comment) |
Beta Was this translation helpful? Give feedback.
-
@dmitriyse Ahh yes, I hadn't thought of that, that does complicate things somewhat. For calling existing Create methods with the constructor syntax that obviously isn't relevant, but going the other way is a little tricky. I don't think the way you've got it in that comment quite works really, either. Off the top of my head, there are two things constructors can do, that other methods can't: write to readonly fields, and call other constructors. An ideal solution would allow both of these. Calling other constructors is probably perfectly doable, that would just be a case of choosing a constructor to use to create the instance in the first place. I think a constructor that was going to compile out to Create would have to be required to call Setting readonly fields outside of the constructor is also (I believe) possible. Yes, I just tested it, it works. So, given all of that, this: class SomeClass
{
private readonly Type type;
// Normal constructor, it's the default but I'm being explicit to show that it's required
private SomeClass() {}
public SomeClass<T>() : this()
{
this.type = typeof(T);
}
} Should be able to compile into this: class SomeClass
{
private readonly Type type;
// Normal constructor, it's the default but I'm being explicit to show that it's required
private SomeClass() {}
public static SomeClass Create<T>()
{
// Creates the instance from a real constructor
// This is aliased as this in the constructor syntax
var instance = new SomeClass();
// This can probably be done nicely in IL, but worst case a readonly field can be set by reflection
typeof(SomeClass).GetField("type").SetValue(instance, typeof(T));
return instance;
}
} Have I missed some obvious thing here? |
Beta Was this translation helpful? Give feedback.
-
@TheOtherSamP Having a compiler feature require compiler hacks that render the assembly unverifiable sounds like a "Bad Idea"™. There is no valid IL to accomplish that either. |
Beta Was this translation helpful? Give feedback.
-
Are you going to get type collision as class SomeClass
{
public SomeClass<T>(){}
}
class SomeClass<T>
{
public SomeClass(){}
} are two different classes and told apart by the constructor invocation; if you gave the non-generic class
|
Beta Was this translation helpful? Give feedback.
-
Oh okay then, I'll bow to your superior knowledge on this one, the compiler and IL really aren't my areas of expertise. I was assuming that the ability to change readonly fields via reflection was in the spec, but it sounds like you're suggesting that it's just an implementation detail. Does de-serialisation not already write to readonly fields? If it's already done somewhere else then it feels defensible here. |
Beta Was this translation helpful? Give feedback.
-
The only things we can do now - is wait for votes counter to reach some valuable amount. Currently we will produce boilerplate factory methods code by hands. |
Beta Was this translation helpful? Give feedback.
-
@benaadams A couple of the comments above (#266 (comment)) were using the |
Beta Was this translation helpful? Give feedback.
-
@benaadams good catch. |
Beta Was this translation helpful? Give feedback.
-
@TheOtherSamP please vote :) |
Beta Was this translation helpful? Give feedback.
-
Java supports generic constructors, though the syntax is slightly different. I've never seen anyone (other than me) writing a generic constructor (other than to test the compiler), but Java should, in theory, provide a rich library of use cases demonstrating why this proposal would be beneficial. Can anyone suggest one such example? |
Beta Was this translation helpful? Give feedback.
-
Hi All, You'll notice that it lets you change/specify generic parameters individually as well.
|
Beta Was this translation helpful? Give feedback.
-
This approach can be useful. And I like it. But it does not solves this proposal. |
Beta Was this translation helpful? Give feedback.
-
No, having exactly one class with multiple generic constructors is your proposed solution. We're still trying to understand the actual problem enough to justify that it involves modifications to the language and likely to the CLR as well. I can see the API that you'd like to have, but I'd like to understand more about what that class actually does with those generic parameters once it has been constructed. I can't imagine it doing anything meaningful, and certainly nothing beyond what is easily solvable today using static factory methods. The latter comes with the added bonus of already having good generic inference whereas constructors don't. |
Beta Was this translation helpful? Give feedback.
-
Constructor is just a method. So probably we can extend C# compiler, Reflection API and probably CLR to allow generic form of a constructor.
This proposal helps to compact a code like that
To
Beta Was this translation helpful? Give feedback.
All reactions