Conclusion from a typical question

I suppose this is more of a public rant, but why can't I get C # to output my identifier?

public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT> 

and a specific EntityObject with a pointer in the form of Id as follows:

 public Foo : EntityObject<Guid> 

Inherited from the abstract EntityObject class defined as follows:

 public abstract class EntityObject<IdT> { public IdT id { get; set; } } 

Using the get method will be as follows:

 IRepository repository = new Repository(); var hydratedFoo = repository.Get<Foo>(someGuidId); 

edited for further clarification.

+6
generics c # types inference
source share
4 answers

It's hard to say, given that you only listed two ads, not how you use them. Is IdT another type parameter somewhere? (If it were a TId , it would suggest that it is - but the fact that you are using EntityT for another type parameter, contrary to conventions, suggests that perhaps IdT too ...)

Now, if IdT is actually Guid in your case, how should the compiler work, what do you mean Foo ? Other types related to EntityObject<Guid> may exist.

In short, you did not give us enough information to say something for sure, but it looks like you basically make unreasonable requirements on the compiler.

EDIT: Okay, here I guess what you have using the usual 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); 

While you should be doing now:

 Foo foo = repository.Get<Foo, Guid>(someGuid); 

Yes, the compiler makes this a little harder for you than necessary. As many as 6 extra characters to keep the language simpler and type inference rules easier to understand.

Basically, type inference is all or nothing — either all type parameters are output, or none of them are. This simplifies the work, since you do not need to determine which ones are indicated and which are not. This part of the problem, and the other part is that you can only express restrictions on the parameters of the method type - you cannot:

 class Repository<TEntity> { TEntity Get<TId>(TId id) where TEntity : EntityObject<TId> } 

since this is a limitation of TEntity , not TId . Again, such things simplify type inference.

Now you can write:

 Foo foo = repository.Get(someGuid).For<Foo>(); 

with the corresponding Get method and an additional interface. I think that personally, I would rather just use Get<Foo, Guid> .

+3
source share

If your method signature looked like this:

 public TEntity Get<TEntity, TId>(TId id) where TEntity : EntityObject<TId> 

The compiler has something to work with ...

Then you call get with something like:

EDIT (I was wrong): Product p = Get (id);

 Product p = Get<Product, Guid>(id); 

John nailed this answer, lifting the top, so I shut up and go back to my hole.

0
source share

Type declaration

 public EntityT Get<EntityT>(IdT id) where EntityT : EntityObject<IdT> 

requires IdT to be a specific type. If you want to also parameterize IdT, you will need to use

 public EntityT Get<EntityT, IdT>(IdT id) where EntityT : EntityObject<IdT> 

But that is probably not what you need.

0
source share

That is why I nevertheless abandoned common key types with generic objects. I could not figure out how to make my objects have common key types without sprinkling them all over the place. Now I settled on integer keys (this is what I have everywhere), but it feels wrong.

0
source share

All Articles