First here's the break down of the class hierarchy:
public class Entity {
}
public abstract class AuditBase<T> {
protected abstract void SomeMethod();
}
public class EntityAudit : AuditBase<Entity> {
protected override void SomeMethod() {
}
}
Then, I have a method with a constraint like so:
public async Task<IEnumerable<T>> Query<T>(int id) where T : AuditBase<T>
{
var instance = Activator.CreateInstance<T>();
var refTable = instance.RefTable;
var collection = _context.Database.GetCollection<T>("Audit");
var filter = String.Join("{ RefTable: '", refTable, "', Object: { Id: {'$eq': ", id.ToString(), "} } }");
return await collection.FindSync<T>(filter).ToListAsync();
}
However, I get an error when I use the following code:
var result = await Query<EntityAudit>(5);
The error is:
The type 'EntityAudit' cannot be used as type parameter 'T' in the generic type of method 'Audit.Query<T>(int)'. There is no implicit reference conversion from 'EntityAudit' to 'AuditBase<EntityAudit>'.
I kind of understand the issue. My goal is really to restrict the returned IEnumerable to only contain objects that are children of AuditBase. Currently, it's trying to return items of type 'Entity' due to T.
I can't do the constraint as so: ... where T: Audit as Audit "requires one parameter."
Any thoughts? How do I implement the constraint?
EDIT:
So I ended up doing the following:
public async Task<IEnumerable<T>> Query<T,U>(int id) where T: AuditBase<U>
{
...
}
var result = await Query<EntityAudit, Entity>(5)
This works.
But, is there a better way?
create a non generic audit base base class
//...
public abstract class AuditBase {
//...
}
public abstract class AuditBase<T> : AuditBase {
protected abstract void SomeMethod();
}
//...
and use that for the constraint
public async Task<IEnumerable<T>> Query<T>(int id) where T : AuditBase {
//...
}
Related
I am trying to implement generic solution using Activator.CreateInstace()
Below I have interface,
public interface INewReleaseValidationRule<T> where T : INewReleaseValidationEntity
{
void Run(CtxNewRelease ctx, IEnumerable<T> entities);
string GetMessage(string messageName, string fallbackMessage);
}
public interface INewReleaseValidationEntity
{}
My class CustomerAssociation is:
public class CustomerAssociation : INewReleaseValidationEntity
{
public void Run(Context.Ctx context, IList<INewReleaseValidationEntity> entitiesObject)
{}
}
Then I have view model which is also implementing INewReleaseValidationEntity.
public class ForecastViewModel : INewReleaseValidationEntity
{
}
Then,
public partial class ValidationRule
{
public void Run(Ctx context, List<ForecastViewModel > entity)
{
var validation = this.GetExecutionType();
var execution = (INewReleaseValidationRule<entity>)Activator.CreateInstance(validation);
execution.Run(context, entity.ToArray());
}
}
In above highlighted statement I am getting error.
If I use,
var execution = (CustomerAssociation)Activator.CreateInstance(validation);
then it works perfectly fine. But I want to provide the explicit type (in this case CustomerAssociation) dynamically.
All my explicit type (that is CustomerAssociation) and others will be inherited from INewReleaseValidationRule<T>.
If I write
var execution = (INewReleaseValidationRule<ForecastViewModel>)Activator.CreateInstance(validation);
then getting runtime error,
Unable to cast object of type 'CustomerAssociation' to type 'INewReleaseValidationRule`1[ForecastEstimateViewModel]'.
It's a bit unclear from the code what the actual intent is, but you can try adjusting your validator's run method to take a generic type like this:
public partial class ValidationRule
{
public void Run<T>(Ctx context, List<ForecastViewModel> entity)
where T : class, INewReleaseValidationEntity
{
var execution = (T)Activator.CreateInstance<T>();
execution.Run(context, entity.ToArray());
}
}
And call it like this:
new ValidationRule().Run<CustomerAssociation(context, entities);
I'm trying to optimize a method and can't get to the solution..
I have the following class:
public class X : MyInterface<Model>
{
public void Execute(Model m) { }
}
I am trying to invoke Execute(...)
I know the Type of X and I know the Type of Model.
This works:
(here logic to find the correct method).Method.Invoke(InstanceX, new object[] { m });
This does not but should work faster:
(here logic to find the correct method).Method.CreateDelegate(Expression.GetDelegateType(typeof(m)), instanceX);
Error:
Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
Again; trying to optimize, so any other solution that works faster than the reflection Invoke would be cool.
Solution without reflection (to create delegate):
// assuming existence of class BaseModel and class XModel : BaseModel
public interface IBaseClass {
void Execute(BaseModel model);
}
public abstract class BaseClass<TModel> : IBaseClass where TModel : BaseModel {
public void Execute(BaseModel model) {
this.Execute((TModel)model);
}
protected abstract void Execute(TModel model);
}
public class X : BaseClass<XModel> {
protected override Execute(XModel model) {
...
}
}
Sample usage:
var typeX = typeof(X);
var typeXModel = typeof(XModel);
var x = (IBaseClass)Activator.CreateInstance(typeX);
x.Execute((BaseModel)Activator.CreateInstance(typeXModel));
I want to create methods that only will able to use if the generic type of a class is from a specific type.
For example, I have two abstract classes NamedEntity and KeyedEntity and I have a class which works with a generic type: MyClass<T>
I would like to create a method X on MyClass<T> which only will be able if the T is a NamedEntity and a method Y on MyClass<T> which only will be able if T is a KeyedEntity. If T is both, both methods will be shown.
I don't want to implement the method independently of the generic type and thrown an error if the type is not the correct type to use the method, but if this is the only way I will do.
If I could inherit from multiple classes it would be easy, but how C#only allow me to inherit from one class it is being hard to think about for me.
EDIT
I agree with all your points. I will try to explain better:
I have an abstract service class, which could work with all the database entities of my system.
All entities could have the "default" methods like "GetById(long id); Create(T entity); Update(T entity)" and it's possible because I am working with an ORM (Nhibernate).
I would like to create the method "GetByName" but not all of the entities have the property "Name", so it will be better if the method GetByName appears only for services which works with a Generic Type that force the entity to have the property "Name", this Generic Type should be the entity class, if I use interfaces (INamedEntity, IKeyedEntity) the problem continue being the same.
If I'm understanding you correctly, you are trying to achieve something like the following (non compilable code follows):
class MyClass<T>
{
public void X(T t) where T: NamedEntity { ... }
public void X(T t) where T: KeyedEntitiy { ... }
}
This won't compile You can not constrain T at method level, only at class level.
Ok. Constraining at top level seems useless, because you'd need to constrain to both NamedEntity and KeyedEntity which is self defeating, so let's constrain at method level:
class MyClass<T>
{
public void X<Q>(Q q) where Q: NamedEntity { ... }
public void X<Q>(Q q) where Q: KeyedEntitiy { ... }
}
Now this won't compile because constraints on generic type parameters are not part of a method's signature. The two methods X would essentially be the same overload and therefore the compiler will flag the second method with an error; method X already exists....
Also, you'd need to check that Q and T are actually compatible and this will only be possible at runtime, not at compile time...yuck!
Ok, then the only option seems to be overloading:
public X(NamedEntity entity) { ... }
public X(KeyedEntity entity) { ... }
Of course this is also far from safe at compile time; you still need to check that the right method is called for the actual type of T and this check can only be done at runtime. Yuck again...
Also, what happens if you have the following:
class Foo: NamedEntity, KeyedEntity { }
myClass.X(new foo()); //now what? What X is called?
This whole setup just seems completely off, you should rethink you approach or give more information on what exactly is it you are trying to achieve.
UPDATE Ok, all clearer now. The methods dont share the same name, thats a big difference!
Based on new info in your question, I would recommend the following approach:
public interface IKeyedIdentity
{
long Id { get; }
}
public interface INamedIdentity: IKeyedIdentity
{
string Name { get; }
}
public class MyClass<T> where T: IKeyedIdentity
{
public void Create(T entity) { ... }
public void Update(T entity) { ... }
public T GetById(long id) { ... }
public Q GetByName<Q>(string name)
where Q : T, INamedEntity
{ ... }
}
Here it makes sense to make the method generic itself because there is a relationship between T and Q you can leverage. This wasn't altogether clear before.
Downside, you have to explicitly supply Q in calls to GetName, I can't think of any compile time safe set up that would avoid this.
UPDATE #2: I think you have to take a step back and implement specialized MyClass<T>s that know how to deal with each expected entity type.
Consider the following code, it should give you enough ideas to implement a similar pattern in your particular scenario:
public static class EntityManagerProvider
{
public static EntityManager<Q> GetManager<Q>()
{
if (typeof(INamedIdentity).IsAssignableFrom(typeof(Q)))
return typeof(NamedEntityManager<>).MakeGenericType(typeof(Q)).GetConstructor(new Type[] { }).Invoke(new Type[] { }) as MyClass<Q>;
if (typeof(IKeyedIdentity).IsAssignableFrom(typeof(Q)))
return typeof(KeyedEntityManager<>).MakeGenericType(typeof(Q)).GetConstructor(new Type[] { }).Invoke(new Type[] { }) as MyClass<Q>;
return null;
}
public abstract class EntityManager<T>
{
public void Create(T entity) { ... }
public void Update(T entity) { ... }
public abstract T GetById(long id);
public abstract T GetByName(string name);
}
private class KeyedEntityManager<Q> : EntityManager<Q> where Q : IKeyedIdentity
{
public override Q GetById(long id) { return default(Q); }
public override Q GetByName(string name) { throw new NotSupportedException(); }
}
private class NamedEntityManager<Q> : EntityManager<Q> where Q : INamedIdentity
{
public override Q GetById(long id) { throw new NotSupportedException(); }
public override Q GetByName(string name) { return default(Q); }
}
}
Now you can do the following:
var myNamedFooManager = MyClassProvider.GetMyClass<NamedFoo>();
var namedFoo = myNamedFooManager.GetByName("Foo"); //I know this call is safe.
var myKeyedFooManager = MyClassProvider.GetMyClass<KeyedFoo>();
var keyedFoo = myNamedFooManager.GetById(0); //I know this call is safe.
Downside: if you need to interact with a given entity that is both keyed and named in either way, you'll have to use two distinct managers.
I want to return the key field by doing something like this:
public virtual int InsertWithReturnId(TEntity entity)
{
dbSet.Add(entity);
return entity.Id;
}
Many thanks
EDIT #1:
I dont need a save changes... it's done like this:
public GenericRepository<Group> GroupRepository
{
get
{
if (this.groupRepository == null)
{
this.groupRepository = new GenericRepository<Group>(context);
}
return groupRepository;
}
}
My pulling (stores successfully the group)
public class GroupMethods
{
private UnitOfWork uow;
public GroupMethods() { this.uow = new UnitOfWork(); }
public int createGroup(string groupName)
{
Debug.WriteLine(groupName);
Debug.WriteLine(HttpContext.Current.User.Identity.GetUserName());
ApplicationUser user = ClanMethods.getUser(HttpContext.Current.User.Identity.GetUserName());
if(groupName != "" && user != null)
{
Debug.WriteLine("inside if");
Group grp = new Group();
grp.creator = user;
grp.Members.Add(user);
grp.GroupName = groupName;
var id = uow.GroupRepository.InsertWithReturnId(grp);
uow.Save();
Debug.WriteLine("id:"+id);
Debug.WriteLine("stops here");
Debug.WriteLine("grp id:"+grp.GroupId);
return id;
}
return 0;
}
}
I was hoping I could do grp.GroupId but it keeps failing, so I guess not. Will update on interface in 20 mins
EDIT #3
I am getting:
Warning 1 Type parameter 'TEntity' has the same name as the type parameter from outer type 'gdfinal.DAL.GenericRepository<TEntity>'
Error 2 The best overloaded method match for 'System.Data.Entity.DbSet<TEntity>.Add(TEntity)' has some invalid arguments
Error 3 Argument 1: cannot convert from 'TEntity [....\DAL\GenericRepository.cs(16)]' to 'TEntity'
Error 4 The type '...chatmodels.Group' cannot be used as type parameter 'TEntity' in the generic type or method '....GenericRepository<TEntity>.InsertWithReturnId<TEntity>(TEntity)'. There is no implicit reference conversion from '....Models.chatmodels.Group' to 'gdfinal.DAL.IIdentifier'.
when using
public virtual int InsertWithReturnId<TEntity>(TEntity entity) where TEntity : IIdentifier
{
dbSet.Add(entity);
return entity.Id;
}
It is successfully inheriting the Interface but really doesnt like it :(
Make an Interface for your EF object to use.
public interface IIdentifier
{
int Id { get; set; }
}
Then change your method (and I assume that TEntity is a generic argument)
public virtual int InsertWithReturnId<TEntity>(TEntity entity)
where TEntity : IIdentifier
{
dbSet.Add(entity);
//save changes()?
return entity.Id;
}
If TEntity is a generic argument on your class, then add the where constraint to the class instead.
Now, because EF auto-generates your classes, use Partials to add the interface (in a separate file)
public partial class <NameOfObject> : IIdentifier { }
Because the class already has a property called Id, you don't have to define it here.
After SaveChanges(), you can get the id value from a model object like your code (return entity.Id)
So, your code would be like this:
public virtual int InsertWithReturnId(TEntity entity)
{
dbSet.Add(entity);
Context.dbSet.SaveChanges();
return entity.Id;
}
I have confusing situation.
Base Generic Type and successor
public abstract class BaseType<TEntity> : where TEntity : BaseType<TEntity>
public class AnyType : BaseType<AnyType>
It looks like a generic loop)))
I need Method like
public void Method<T>(T data)
{
if(typeof(T).IsSubclassOf(BaseType<????>))
convert data to BaseType<???> and exec BaseType<>'s method
else
//Do that
}
In generic Method i need to defines that T is BaseType and exec method on it.
How can I do that????
You can use reflection and work your way up the hierarchy using Type.BaseType. Note that depending on the exact concrete class, the base type could still be an open generic type, e.g.
class Foo<T> : BaseType<T>
You can use Type.IsGenericTypeDefinition and Type.GetGenericTypeDefinition to try to work your way to BaseType<>. Basically you want to find out whether any class in the inheritance hierarchy has a generic type definition which is typeof(BaseType<>). Just be glad you're not dealing with interfaces, which make the whole thing even harder :)
You can use the following code:
static bool IsBaseType<T>()
{
var t = typeof(T);
do
{
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(BaseType<>))
{
return true;
}
t = t.BaseType;
}
while (t != null);
return false;
}
A common pattern in this case is to have a non-generic base type of the generic base type. If your method doesn't involve the type parameter, then you're done. If it does, you could add a non-generic method that does a typecast, similar to Object.Equals:
public abstract class ReallyBaseType
{
public abstract void SomeMethod();
public abstract void SomeMethodWithParameter(object o);
}
public abstract class BaseType<TEntity> : ReallyBaseType
where TEntity : BaseType<TEntity>
{
public override void SomeMethodWithParameter(object o)
{
SomeMethodWithParameter((TEntity)o);
}
public abstract void SomeMethodWithParameter(TEntity entity);
}
public class AnyType : BaseType<AnyType>
{
public override void SomeMethod() { }
public override void SomeMethodWithParameter(AnyType entity) { }
}
Then, you can just check the actual type of data:
public void Method<T>(T data)
{
if (data is ReallyBaseType)
{
((ReallyBaseType)(object)data).SomeMethod();
}
}
EDIT: I think you're stuck using reflection, then. If you want to be able to write code against the concrete type, you could create a generic method and invoke it using reflection:
public class TestClass
{
private static MethodInfo innerMethodDefinition =
typeof(TestClass).GetMethod("InnerMethod");
public void Method(object data)
{
var t = data.GetType();
while (t != null &&
!(t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof(BaseType<>)))
{
t = t.BaseType;
}
if (t != null &&
t.GetGenericArguments()[0].IsAssignableFrom(data.GetType()))
{
innerMethodDefinition.MakeGenericMethod(
t.GetGenericArguments()[0]).Invoke(this, new object[] { data });
}
}
public void InnerMethod<TEntity>(TEntity data)
where TEntity : BaseType<TEntity>
{
// Here you have the object with the correct type
}
}