As discussed here, C# doesn't support generic attribute declaration.
So, I'm not allowed to do something like:
[Audit<User> (UserAction.Update)]
public ActionResult SomeMethod(int id){ ...
that would fit like a charm in my attribute impl class, cause I need to call a method from a generic repository:
User fuuObj = (User) repository.LoadById<T>(_id);
I tried to use this solution without success. I can pass something like typeOf(User), but how can I call LoadById just with type or magic string?
*Both, T and User, extend a base class called Entity.
You could use reflection to load by id:
public class AuditAttribute : Attribute
{
public AuditAttribute(Type t)
{
this.Type = t;
}
public Type Type { get; set; }
public void DoSomething()
{
//type is not Entity
if (!typeof(Entity).IsAssignableFrom(Type))
throw new Exception();
int _id;
IRepository myRepository = new Repository();
MethodInfo loadByIdMethod = myRepository.GetType().GetMethod("LoadById");
MethodInfo methodWithTypeArgument = loadByIdMethod.MakeGenericMethod(this.Type);
Entity myEntity = (Entity)methodWithTypeArgument.Invoke(myRepository, new object[] { _id });
}
}
You have at least these three possibilities:
You could use reflection to call LoadById
You could create an expression tree that calls LoadById
You could provide a LoadById method in your repository that is not generic.
You could use reflection to invoke the LoadById method. The following msdn article should point you in the right direction:
http://msdn.microsoft.com/en-us/library/b8ytshk6(v=vs.100).aspx
Since C# 11 there is no need for workarounds because generic attributes are supported:
public class AuditAttribute<T> : Attribute where T : Entity
{
// ...
}
Related
Yesterday, I was explaining C#'s generic constraints to my friends. When demonstrating the where T : CLASSNAME constraint, I whipped up something like this:
public class UnusableClass<T> where T : UnusableClass<T>
{
public static int method(T input){
return 0;
}
}
And was really surprised to see it compile. After a bit of thinking, however, I figured it was perfectly legal from the point of view of the compiler - UnusableClass<T> is as much of a class as any other that can be used in this constraint.
However, that leaves a couple of questions: how can this class ever be used? Is it possible to
Instantiate it?
Inherit from it?
Call its static method int method?
And, if yes, how?
If any of these is possible, what would the type of T be?
This approach is widely used in Trees and other Graph-like structures. Here you say to compiler, that T has API of UnusableClass. That said, you can implement TreeNode as follows:
public class TreeNode<T>
where T:TreeNode<T>
{
public T This { get { return this as T;} }
public T Parent { get; set; }
public List<T> Childrens { get; set; }
public virtual void AddChild(T child)
{
Childrens.Add(child);
child.Parent = This;
}
public virtual void SetParent(T parent)
{
parent.Childrens.Add(This);
Parent = parent;
}
}
And then use it like this:
public class BinaryTree:TreeNode<BinaryTree>
{
}
Well.
public class Implementation : UnusableClass<Implementation>
{
}
is perfectly valid, and as such makes
var unusable = new UnusableClass<Implementation>();
and
UnusableClass<Implementation>.method(new Implementation());
valid.
So, yes, it can be instantiated by supplying an inheriting type as the type parameter, and similarly with the call to the static method. It's for instance useful for tree-like structures where you want to generically specify the type of children the node has, while it being the same type itself.
If any of these is possible, what would the type of T be?
They are all possible, and you are the one who is gonna determine what is the type of T.For example let's assume there is a type that inherits from UnusableClass<T>
class Foo : UnusableClass<Foo> { }
Now you can instantiate UnusableClass<Foo> because Foo satisfies the constraint:
UnusableClass<Foo> f = new UnusableClass<Foo>();
Then the type of T become Foo and if you try to call method you need to pass an instance of Foo.
I believe this is the only way to achieve what I want but I wanted to put this out there to see if there's a solution that doesn't require using dynamic/reflection.
I have the following hierarchy of types, stripped to the bare essentials to demonstrate the point:
// Validators:
public abstract class Validator<T> { }
public class RequiredValidator<T> : Validator<T> { }
// Fields:
public abstract class Field { }
public abstract class Field<T> : Field
{
public void AddValidator(Validator<T> validator) =>
Console.WriteLine($"Added validator {validator.GetType()}");
}
public sealed class ValueField<T> : Field<T> { }
public sealed class ComputedField<T> : Field<T> { }
...many other field types that inherit Field<T>
This is an example usage of the fluent interface I want to achieve:
ValueField<string> field1 = new ValueField<string>().Required();
The Required() method must be available on all types that inherit Field<T>.
This is what I've come up with:
public static class Extensions
{
public static TField Required<TField, T>(this TField field) where TField : Field<T>
{
field.AddValidator(new RequiredValidator<T>());
return field;
}
public static TField DynamicRequired<TField>(this TField field) where TField : Field
{
DynamicAddRequiredValidator((dynamic)field);
return field;
}
private static void DynamicAddRequiredValidator<T>(Field<T> field)
{
field.AddValidator(new RequiredValidator<T>());
}
}
void Main()
{
// This is desired API usage but results in error:
// The type arguments for method 'Extensions.Required<TField,T>(TField)' cannot be inferred from the usage.
ValueField<string> field1 = new ValueField<string>().Required();
// This works but the user shouldn't have to specify types like this, makes it very annoying to use:
ValueField<string> field2 = new ValueField<string>().Required<ValueField<string>, string>();
// This works but requires dynamic:
ValueField<string> field3 = new ValueField<string>().DynamicRequired();
}
Am I missing a way of achieving this which avoids using dynamic based code?
Generics in C# are an all or nothing. You either pass all, like you've done, or none. It must be designed in a way that all arguments can be inferred. For what you're doing you can just use Field<T> instead of TField<T>, removing that generic type parameter; although it may not be as ideal. There are other ways... Some FLUENT designs return new types that contain the generics as properties allowing you to move forward but your continuation would need the logic of using that continue type as well. It gets a bit confusing but I feel you understand. If not let me know.
It would be nice if the where constraint could also help infer the types but it doesn't. Eric Lippert recently helped me understand that C# tries to infer the generic parameters only and if that can't be inferred it fails. The where constraint is only to limit the generic type to a base and inform developers. Although it does feel like we could also infer based on constraints, since we are basing the types, C# doesn't. Eric has an opinion about not doing so, which I'm sure is more than I understand ATM. Either way, there you have it.
For "extendable" fluent interface, we use following trick in Java (you can try, if it's possible in C# too):
public class Field<L extends Field<L, V>, V> {
public L required() {
//...
return (L) this;
}
}
public class ValueField<V> extends Field<ValueField<V>, V> {
}
Now you can call what you need:
ValueField<String> v = new ValueField<String>().required();
It's thanks to additional type parameter of Field which delegates specific return type of the fluent methods to children.
I've already research a lot about the question and already know the direct answer. You can't override a base method with new parameter. Thing is, what I want to do is simple yet I don't know what to look for or if what I want to do is non-sense so if anybody can point me to a direction that would be great.
Here's what I want to do. I have a base class with a method call Create. This methods takes a Type argument and uses reflection to create the associate object with its properties. Its works great with whatever type I pass as an argument but now I want this method to return the said type pass in the parameter to add it to a list. Naturally I just added a return to the created model but I can't add a Type object to my List Student (My own type here). So what I tried was to create a derived class and in that class change the parameter from Type to Student. Obviously this doesn't work but now I am stuck. My base method works perfectly (other than the fact it doesn't return what I want) and I would like to only modify the return type on my derived class. Here's the snippet of the code. (NOTE: I am french)
abstract class ControllerBase
{
public virtual Type Create(ControlContainer controlContainer, Type typeToCreate)
{
dynamic returnObject = null;
//Stuff that creates my returnObject
return returnObject;
}
}
class StudentControl : ControllerBase
{
static public List<Student> Students{ get; set; }
public Type Create(ContainerControl containerControl, Type typeToCreate)
{
typeToCreate = typeof(Student);
return base.Create(containerControl, typeToCreate);
}
}
So, this is basically what I want to do. Transform the return type of my base method to another type in my derived class in order to add it to my Student list. I've looked around but don't really what to look for here. I can't use a <T> generic method here because reflection doesn't work on generic type.
Who said that reflection doesn't work with generics?
abstract class ControleurBase
{
public virtual T Créer<T>(ConteneurControle conteneurControle)
{
var actualType = typeof(T); // use this instead of the Type parameter
dynamic modele = null;
//Stuff that creates my model
return (T)modele;
}
}
class ControleurÉtudiant : ControleurBase
{
public static List<Étudiant> Etudiant { get; set; }
public Étudiant Créer(ConteneurControle conteneurControle)
{
return base.Créer<Étudiant>(conteneurControle);
}
}
By the way, you really shouldn't write code that's not in English. It makes it hard for anyone who doesn't speak French.
Sorry couldn't find a relevant SO question.
I use Reflection to get a property (which is another object) of an object using:
public static T GetPropertyValue<T>(this object obj, string propertyName)
{
PropertyInfo prop = obj.GetType().GetProperty(propertyName);
return (T)prop.GetValue(obj, null);
}
I have a (Xero) Api that looks like:
public class XeroCoreApi : XeroApi
{
public AccountsEndpoint Accounts { get; }
public ContactsEndpoint Contacts { get; }
// ...
}
Where the Endpoints inherit a class that looks like:
public abstract class XeroUpdateEndpoint
{
public TResult Update(TResult item);
// ...
}
i.e. I can call updates on the specific entities:
Contacts.Update(...);
When I do call the GetPropertyValue() method I get the Endpoint object from an instance of the XeroCoreApi but I don't know it's methods (really I do, but the compiler doesn't) until run-time.
To obtain the Endpoint I run the command similar to:
var endpoint = _api.GetPropertyValue<object>("Contacts");
// For the sake of this example the "Contacts" is manually
// entered, violating the whole idea of generics
The problem is I can't do something like endpoint.Update(...) (since the endpoint is a var and some endpoint don't particularly inherit the Update() method).
Is it possible to run the method using Reflection? What might the syntax look like?
Summary:
How to call a method (Update()) of an object of type T (i.e. we don't know the object until run-time) using reflection?
E.g. endpoint.Update(...)
If I understand you correctly, you want generic type constraints (not reflection). This gives the compiler the proof that your type satisfies some conditions.
For example, an interface:
public interface IUpdateStuff {
void Update();
}
public class XeroCoreApi : XeroApi, IUpdateStuff {
// implementation here
}
Then you can constrain your generic type:
public TResult Update(TResult item) where TResult : IUpdateStuff ;
Now the compiler will let you:
public TResult Update(TResult item) where TResult : IUpdateStuff {
item.Update(); // <-- this is okay now.
}
EDIT: This assumes your generic type comes from the enclosing class.. which it appears to in your example.
Is there a way to specify in type parameters that a parameter is the type of the object instance?
For instance, to illustrate, I have:
public abstract class Model
{
public int Prop1 { get; set; }
}
For my example, I want to have a method that will return a property of the Model passed in (obviously this is a stupid method, but it gets the point across). I can make it work as an extension method:
public static class Extensions
{
public static U Property<T, U>(this T model, Expression<Func<T, U>> property) where T : Model
{
return property.Compile().Invoke(model);
}
}
this way I can have
public class DerivedModel : Model
{
public string Prop2 { get; set; }
}
and do
var myString = new DerivedModel().Property(a => a.Prop2);
This method seems like it should be part of the Model class, and look something like:
public T Property<T>(Expression<Func<ThisDerivedInstanceOfModel, T>> property)
{
return property.Compile().Invoke(this);
}
so that the same call to Property() that the extension method does can execute on an instance of a Model.
I realize that this is kind of bizarre and may simply not be a feature of C#, and the workaround extension method works perfectly well - but I'd much prefer to make this an instance method if possible, since seems 'better' to me.
Is there a way to specify in type parameters that a parameter is the type of the object instance?
Nope. Sorry. There are times when I can see it being useful, but it's not something you can do. I've had similar issues in the past :(