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.
Related
In the code below, I want to use an action having a more derived parameter pass into an action using the base as a parameter. The code looks like this:
public interface IContext<T>
{
}
public interface IWorkflow<T>
{
void Do(Action<IContext<T>> lambda);
}
public interface IDerivedContext : IContext<int>
{
}
public interface IDerivedWorkflow : IWorkflow<int>
{
void Do(Action<IDerivedContext> lambda);
}
public class Workflow<T> : IWorkflow<T>
{
public void Do(Action<IContext<T>> lambda)
{
Console.WriteLine("in Do(Action<IContext<T>>");
}
}
public class DerivedContext : IContext<int>
{
}
public class DerivedWorkflow : Workflow<int>, IDerivedWorkflow
{
public void Do(Action<IDerivedContext> lambda)
{
base.Do(lambda); // Compiler error:
}
}
If I cast this line:
base.Do(lambda);
like this:
base.Do((Action<IContext<int>>)lambda);
The compiler accepts the cast but code fails at runtime with an InvalidCastException.
Based on the MSDN documentation it suggests that the above should work because I'm passing an Action with a parameter of a more derive class to an Action using a parameter of a least derived class (in this case the base class) for example the docs illustrates the following:
static void AddToContacts(Person person)
{
// This method adds a Person object
// to a contact list.
}
static void Test()
{
// Create an instance of the delegate without using variance.
Action<Person> addPersonToContacts = AddToContacts;
// The Action delegate expects
// a method that has an Employee parameter,
// but you can assign it a method that has a Person parameter
// because Employee derives from Person.
Action<Employee> addEmployeeToContacts = AddToContacts;
}
}
Am I misunderstanding something or is there a workaround to this problem.
Thanks in advance
That's fundamentally unsafe; you can't do that.
An Action<IDerivedContext> can only take an IDerivedContext as a parameter. Had you been able to convert it to Action<IContext<int>>, you would be able to call it with some other IContext<int> implementation that it can't actually accept.
I have an app written in C#. My app has a class that looks like the following:
public class FinderA
{
public IEnumerable<FinderA> GetItems()
{
return FinderA.FindAll();
}
}
I want to require other classes to do something similar. I cannot use a base class because my actual implementation is already using a base class. For that reason, I want to create an interface. Currently, I'm trying the following:
public interface IFinder
{
IEnumerable<T> GetItems();
}
When I use this approach, I get a compile-time error that says: "The type or namespace name 'T' could not be found (are you missing...". To overcome this, I add <T> to the end of the interface name so it looks like this:
public interface IFinder<T>
{
IEnumerable<T> GetItems();
}
This is turn generates another compile-time error that says: "Using the generic type 'IFinder' requires 1 type arguments.". My challenge is, I want the interface to be generic. I do not want to pass in a type. Is there a way around this? If so, what/how?
There is no way around this; you'll need to actually supply the generic type argument when declaring that a class implements the interface.
You can do this at the method level instead of as a generic type on the interface itself.
public interface IFinder
{
IEnumerable<T> GetItems<T>();
}
Your code can then call it like such:
IFinder finder = // Create finder instance
IEnumerable<MyClass> discoveredClasses = finder.GetItems<MyClass>();
If you want to ensure that MyClass is a class that implements IFinder, you can constrain the method.
public interface IFinder
{
IEnumerable<T> GetItems<T>() where T : IFinder;
}
That will cause the following to generate a compiler error:
public class Foo
{
}
public class Bar
{
Bar()
{
IFinder finder = // Create finder.
// This fails because <T> (Foo) does not implement IFinder.
IEnumerable<Foo> fooItems = finder.GetItems<Foo>();
}
}
but it will allow the following to compile
public class MyFinderA : IFinder
{
IEnumerable<T> GetItems<T>() where T : IFinder
{
return // Create collection of T
}
public class Bar
{
Bar()
{
IFinder finder = // Create finder.
// This works as <T> (MyFinderA) is an IFinder implementation
IEnumerable<MyFinderA> finderItems = finder.GetItems<MyFinderA>();
}
}
If you want your interface to be generic but you are not willing to supply a type argument, you can return an IEnumerable<object>.
public interface IFinder {
IEnumerable<object> GetItems();
}
All class types extend from System.Object so that should suffice for any type in your applicacion (enums and structs would get boxed)
Please note that this approach requires the interface's consumer to cast the generic object instances to the appropiate types.
The alternate (and recommended) approach is to make the interface use type parameters, but for that you must supply the appropiate type arguments
I'm approaching a problem while still having some ignorance regarding Generics and their proper declarations / uses. I get the premiss, but some of the ins-n-outs of generics still elude me.
Given the following code (does not compile and contains code-smell):
public interface IUIConcern<out T> where T : IUIConcernExtension
{
string Name { get; }
Func<T> Extend();
}
public class UIConcern
{
public static void Register<T>(string concernName, IUIConcern<T> uiConcern) where T : IUIConcernExtension
{
Concerns.Add(uiConcern);
}
public static List<IUIConcern<T>> Concerns{
get {
// Logic...
}
set {
// Logic...
}
}
}
... I have a few questions:
Why do I have to specify this part public static void Register<T>(string concernName, IUIConcern<T> uiConcern) where T : IUIConcernExtension
with a constraint when I have already constrained the T in the declaration public interface IUIConcern<out T> where T : IUIConcernExtension
How can I have a property that holds a List<> of my IUIConcern<T> without knowing T other than knowing it will be derived from IUIConcernExtension?
Again, I realize this doesn't compile and is not correct, just looking to see how I can hold a list of generic items that may have many different type of IUIConcern<> elements.
Thank you!
You need to have a base interface, for instance:
public interface IUIConcern
{
string Name { get; }
}
public interface IUIConcern<out T> : IUIConcern where T : IUIConcernExtension
{
Func<T> Extern();
}
How you would define Concerns and Register would depend on how you treat T. Alternatively if you only deal with instances where you know T, you could use a Dictionary<Type, List<IUIConcern>> to hold anything, or potentially drop the base interface and just store using object depending on what you need in your controller code.
The problem is not located at the interface, but the problem is because of your generic implementation using static methods and properties.
The answer from Guvante was correct when saying that you need to define the IUIConcernExtension, but that is of course very logical, so im assuming you have just omitted that part since it does not matter for the issue you are facing.
The problem in the code is that you have created a class that has static methods and procedures, with the generic definition not laying at class level, but at methods level, because of this, the property that has and the Method cannot assume you are always with the same type!!
Lets say you call call :
Register<string>("something", UIConcern<string>)
but before that you have already called:
Register<Type>("something", UIConcern<Type>)
How could the compiler allows you to that?! So the answer is to define the generic type at class level, with this all properties and methods will be of same .
Also you need to use a private member for your list, since you doing everything static, the correct code should be:
interface IUIConcernExtension
{
string Name { get; }
}
public interface IUIConcern<out T> where T : IUIConcernExtension
{
Func<T> Extend();
}
public class UIConcern<T> where T : IUIConcernExtension
{
private static List<IUIConcern<T>> _Concerns = new List<IUIConcern<T>>();
public static void Register(string concernName, IUIConcern<T> uiConcern)
{
Concerns.Add(uiConcern);
}
public static List<IUIConcern<T>> Concerns
{
get { return _Concerns; }
set { _Concerns = value; }
}
}
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
{
// ...
}
When i need to pass a Generic Type I can use the Syntax
(Example : Ofcourse it is not a Generic Method)
public void Sample(T someValue)
{
......
}
What is the benefit of declaring Sample<T> ?
I mean
public void Sample<T> (T someValue)
{
......
}
Generic types and generic methods are very different things. It sounds like you have a generic type:
class SomeType<T> {
public void Sample(T someValue) {...}
}
and are discussing having a generic method inside it:
class SomeType<T> {
public void Sample<T>(T someValue) {...}
}
These are very different. In the first, inside Sample, then T means "the T that got passed to SomeType<T>". In the second, inside Sample, this is a separate and independent T - "the T that got passed to Sample<T>". In fact, calling it T (in this case) is a mistake. You could have, for example:
var obj = new SomeType<int>(); // here T for SomeType<T> is int
obj.Sample<decimal>(123.45M); // here T for Sample<T> is decimal
Note that there is no easy way (within Sample<T>) of saying "the T in SomeType<T>" - hence why you should rename the method's generic type parameter.
There are valid scenarios for this type of scenario (generic methods on generic types), for example (and note the new name):
class SomeType<T> {
public void Sample<TActual>(TActual someValue) where TActual : T, new() {...}
}
This allows us to do some very interesting things in terms of inheritance, etc - or you might want a generic method that has little or no relation to T. That is fine too.
For this to work:
public void Sample(T someValue)
{
......
}
The type T has to be declared in the system already. And the method will only accept the type T or its derivatives.
By declaring this:
public void Sample<T> (T someValue)
{
......
}
you say the method will accept any type that comes.
Consider the following:
class SomeClass<T>
{
public void Sample(T value)
{
// code goes here
}
}
or this:
class SomeClass
{
public void Sample<T>(T value)
{
// code goes here
}
}
In the first case, for all calls to Sample in a specific instance T will be the same type. In the second case each call in a specific instance can have its own type of T, since the generic type argument is supplied with the method call.
The second approach can have many uses, but one that I have used myself sometimes is in factory methods:
public static class SomeFactory
{
public static T CreateSomeObject<T>()
{
T result = Activator.CreateInstance<T>();
// perform any extra initialization
return result;
}
}
You can use the 2nd example if your class isn't generic. It means you can make just that method generic. If your class is generic, you should use your 1st example.