I suppose this is more of a public rant, but why can't I get c# to infer my Id's type?
public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT>
and a defined EntityObject with a Guid as an Id as follows:
public Foo : EntityObject<Guid>
Inheriting from the abstract EntityObject class defined as follows:
public abstract class EntityObject<IdT>
{
public IdT id { get; set; }
}
Usage of the get method would be as follows:
IRepository repository = new Repository();
var hydratedFoo = repository.Get<Foo>(someGuidId);
edited to provide further clarification.
Type inference is when the compiler can look at the type of a method argument to infer a generic type. For example, if we passed in T to a method which returns T, then the compiler can figure out the return type. Let's try this out by invoking our generic method from the previous question:
If you are asked a question about a text that you've read thoroughly, just about any inference you make, as long as it is supported by evidence and answers the question in its entirety, can be considered correct.
A generic method is where a type parameter is introduced to a method, living within the scope of that method. Let's try this with an example: We've used a static method but could have also used a non-static one if we wished.
The reasoning behind major implementation choice is simple – preserving backward compatibility with older versions of Java. When a generic code is compiled into bytecode, it will be as if the generic type never existed. This means that the compilation will:
It's hard to say given that you've only given two declarations, not how you're using them. Is IdT another type parameter somewhere? (If it were TId
, that would suggest it is - but the fact that you're using EntityT
for another type parameter, contrary to conventions, suggests that maybe IdT
is as well...)
Now, assuming IdT
is actually Guid
in your case, how should the compiler work out that you mean Foo
? There could be other types deriving from EntityObject<Guid>
.
In short, you haven't given us enough information to tell anything for sure, but it sounds like you're basically making unreasonable demands on the compiler.
EDIT: Okay, here's my guess at what you have, using normal naming conventions:
public interface IRepository
{
TEntity Get<TEntity, TId>(TId id) where TEntity : EntityObject<TId>
}
public abstract class EntityObject<TId>
{
public IdT id { get; set; }
}
public class Foo : EntityObject<Guid> {}
You want to do:
IRepository repository = GetRepositoryFromSomewhere();
Foo foo = repository.Get<Foo>(someGuid);
Whereas currently you have to do:
Foo foo = repository.Get<Foo, Guid>(someGuid);
Yes, the compiler is making it very slightly harder for you than necessary. A whole 6 extra characters, for the sake of keeping the language simpler and the rules of type inference easier to understand.
Basically type inference is an all or nothing affair - either all type parameters are inferred or none of them is. That keeps it simple as you don't need to work out which ones are being specified and which aren't. That's part of the problem, and the other part is that you can only express constraints on the type parameters of the method - you can't have:
class Repository<TEntity>
{
TEntity Get<TId>(TId id) where TEntity : EntityObject<TId>
}
because that's constraining TEntity
, not TId
. Again, this sort of thing makes type inference simpler.
Now you could potentially write:
Foo foo = repository.Get(someGuid).For<Foo>();
with an appropriate Get
method and an extra interface. I think I'd personally prefer to just use Get<Foo, Guid>
though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With