Inheriting Generic Type contraints #1390
Replies: 11 comments
-
https://ericlippert.com/2013/07/15/why-are-generic-constraints-not-inherited/ |
Beta Was this translation helpful? Give feedback.
-
@e-davidson , I whole-heartedly agree with your sentiments. In fact, I have some classes that are much more involved with type constraints and would benefit greatly from "constraint inheritance." For example, public abstract class TemporalRepoTests<TTemporalRepo, TEntity, THistoryEntity, TContext, THistoryContext>
: IClassFixture<TestTemporalRepoFixture<TTemporalRepo, TEntity, THistoryEntity, TContext, THistoryContext>>, IDisposable
where TEntity : class, IEFCoreTemporalModel, new()
where THistoryEntity: TEntity
where TContext : ResettableDbContext<TContext>
where THistoryContext : ResettableDbContext<THistoryContext>
where TTemporalRepo : TemporalRepo<TEntity, THistoryEntity, TContext, THistoryContext> {
//...
} I read the blog post referenced by @jnm2, but I don't see how the complexity of the types (even with nested type constraints) would prevent proper inference. For those edge cases where the inference would not work well, the developer could supply the type constraints explicitly. |
Beta Was this translation helpful? Give feedback.
-
I'd say more so. |
Beta Was this translation helpful? Give feedback.
-
Generic type constraints are part of a method's signature. C# does not like inferring any part of a method signature (or any other contract, e.g. a field's type). If a method signature changes, you're probably breaking binary compatibility. Therefore such a change should be a conscious decision by the developer, and should not happen by accident. Inheriting generic type constraints would mean that it would be easy to accidentally break binary compatibility of a method by changing something apparently unrelated. This is the same reason that I do think that this is a place where a code fix could help, by offering to change the generic type constraints on a method to eliminate a CS0425 error. |
Beta Was this translation helpful? Give feedback.
-
@canton7, is the "code fix" you are suggesting a Visual Studio enhancement ... when the CS0425 error is encountered, provide a quick fix option that generates the type constraints or replaces existing incorrect type constraints? Or perhaps a "wh TAB TAB" built-in code snippet that generates all of the constraints? That would be nice. In my particular case, it would be helpful to add an expand/collapse section around the constraints, but I would take the "wh TAB TAB" without the expand/collapse or the quick fix, if that's all that could be done. I'm not a compiler guy, so please forgive me if I am way off the mark, but your discussion of binary compatibility makes me think about default constructors for classes. For two otherwise identical classes where one class has an explicit default constructor in the source code and the other class does not have any constructor in the source code, could these two classes be binary compatible? If so, then does/should binary compatibility always depend upon inclusion of key features of a class or method? Should we require explicit default constructors? |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
@canton7 I think he is asking why the line would be drawn such that default constructors would be inferred (implicitly affecting API compatibility) but generic constraints would not be also inferred with the same implicit effect. Maybe the answer is that implicit default constructors aren't a common pit of failure, but inferred signatures would be. |
Beta Was this translation helpful? Give feedback.
-
I see. Adding a default constructor does not break binary compatibility. You move from the class having a compiler-generated default constructor, to a user-specified default constructor. There is a default constructor in both cases (with the same signature), so binary compatibility is not broken. However, adding generic type constraints to a method (or type) may break binary compatibility. Let's say your assembly A defines a method |
Beta Was this translation helpful? Give feedback.
-
@canton7 The implicit default constructor feature can amount to a subtractive API change when you first begin to explicitly declare a constructor with parameters. |
Beta Was this translation helpful? Give feedback.
-
Right, yes that is true. To trigger this, though, you need to make a change to the constructors of the affected class. There's a conscious action when editing that class. With this proposal, a change to a method in one class could unintentionally break the compatibility of a method in an entirely different class, which is perhaps declared in a different assembly. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure I'm following. You're saying that a change in a base class can break a derived class which may be in a different assembly. There are lots of changes that can be done to a base class that can break a derived class. Even if you need to specify generic type constraints manually you can still break a derived class by just by changing the constraints of the base class. I don't see why using something as default changes that in any way. Please pardon my ignorance, I'm just not seeing it. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Currently all derived classes that are generic and also derive from a generic type with the same type parameter need to specify all the generic constraints. Otherwise you'll get
The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'Repository<T>'
.See the following code
There is no way to implement the derived classes without specifying the same constraints over and over again.
Is there any benefit to explicitly stating the same constraints?
Can we have all constraints that you're forced to implement be implicit?
The compiler obviously already knows that you need those constraints as seen in the compiler error.
Beta Was this translation helpful? Give feedback.
All reactions