C# - Using attributes and reflection in a command tool [duplicate] - c#

This question already has answers here:
How enumerate all classes with custom class attribute?
(8 answers)
Closed 3 years ago.
I'm working on a command tool in C#, although not for a terminal command-line. I have read the documentation on reflection and attributes but I'm not sure exactly what the "right" way to go about this is.
The problem isn't very complicated, but it needs to be easily extended. I need to just have Commands that are picked up and loaded in where their triggering strings are checked and if they match, methods are called. How I went about it just as a proof-of-concept was:
[System.AttributeUsage(System.AttributeTargets.Class)]
public class CommandAttribute : Attribute
{
public string Name { get; private set; } //e.g Help
public string TriggerString { get; private set; } //e.g. help, but generally think ls, pwd, etc
public CommandAttribute(string name, string triggerStrings)
{
this.Name = name;
this.TriggerString = triggerString;
}
}
Now, I decorated the class and it will implement methods from an interface. Eventually there will be many commands and my idea is to make it easy for someone with minimal programming experience to jump in and make a command.
using Foo.Commands.Attributes;
using Foo.Infrastructure;
namespace Foo.Commands
{
[Command("Help", "help")]
public class Help : IBotCommand
{
// as an example, if the message's contents match up with this command's triggerstring
public async Task ExecuteAction()
}
}
This gets injected into the console app where it will load the commands and get passed messages
public interface ICommandHandler
{
Task LoadCommands();
Task CheckMessageForCommands();
}
Then, everything with a matching attribute will get loaded in and when a message is received, it will check its contents against all CommandAttribute decorated classes' triggering strings, and if it matches, call the method ExecuteAction on that command class.
What I've seen/tried: I understand how to use reflection to get custom attribute data, however I'm confused as to getting the methods and calling them, and how all of this should be configured to be fairly performant with reflection being used. I see CLI tools and chat bots that use a similar method, I just cannot peek into their handlers to see how these get loaded in and I can't find a resource that explains how to go about accessing the methods of these classes. Attributes may not be the right answer here but I'm not sure how else to go about it.
Really, my main question is:
How do I setup The CommandHandler to load all of the attribute-decorated classes and call their methods, and how they should be instantiated within it. I know the second piece may be a bit more subjective but would newing them up be improper? Should they somehow be added to DI?
My solution ended up just using the Activator and lists. I still need to tweak this for performance and run more extensive stress tests, but here is my quick code for it:
// for reference: DiscordCommandAttribute is in Foo.Commands library where all the commands are, so for now it's the target as I removed the base class
// IDiscordCommand has every method needed, so casting it as that means down the line I can call my methods off of it. The base class was just for some reflection logic I was testing and was removed, so it's gone
public void LoadCommands() // called in ctor
{
var commands =
from t in typeof(DiscordCommandAttribute).Assembly.GetTypes()
let attribute = t.GetCustomAttribute(typeof(DiscordCommandAttribute), true)
where attribute != null
select new { Type = t, Attribute = attribute };
foreach (var obj in commands)
{
_commandInstances.Add((IDiscordCommand)Activator.CreateInstance(obj.Type));
_commandAttributes.Add(obj.Attribute as DiscordCommandAttribute);
}
}
There is probably a more sugary way to handle adding the objects to the lists, and some other data structure besides Lists might be more suitable, I'm just not sure if HashSet is right because it's not a direct Equals call. Eventually I will genericize the interface for this class and hide all of this logic in a base class. Still a lot of work to do.
Currently, just putting a stopwatch start before calling LoadCommands shows that the entire load takes 4ms. This is with 3 classes and a pretty anemic attribute, but I'm not too worried about the scale as I want any overhead on launch and not during command handling.

Using some code I wrote for this answer, you can find all types that implement an interface, e.g. IBotCommand, and then retrieve the custom attribute:
public static class TypeExt {
public static bool IsBuiltin(this Type aType) => new[] { "/dotnet/shared/microsoft", "/windows/microsoft.net" }.Any(p => aType.Assembly.CodeBase.ToLowerInvariant().Contains(p));
static Dictionary<Type, HashSet<Type>> FoundTypes = null;
static List<Type> LoadableTypes = null;
public static void RefreshLoadableTypes() {
LoadableTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetLoadableTypes()).ToList();
FoundTypes = new Dictionary<Type, HashSet<Type>>();
}
public static IEnumerable<Type> ImplementingTypes(this Type interfaceType, bool includeAbstractClasses = false, bool includeStructs = false, bool includeSystemTypes = false, bool includeInterfaces = false) {
if (FoundTypes != null && FoundTypes.TryGetValue(interfaceType, out var ft))
return ft;
else {
if (LoadableTypes == null)
RefreshLoadableTypes();
var ans = LoadableTypes
.Where(aType => (includeAbstractClasses || !aType.IsAbstract) &&
(includeInterfaces ? aType != interfaceType : !aType.IsInterface) &&
(includeStructs || !aType.IsValueType) &&
(includeSystemTypes || !aType.IsBuiltin()) &&
interfaceType.IsAssignableFrom(aType) &&
aType.GetInterfaces().Contains(interfaceType))
.ToHashSet();
FoundTypes[interfaceType] = ans;
return ans;
}
}
}
public static class AssemblyExt {
//https://stackoverflow.com/a/29379834/2557128
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null)
throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
Note: If you create types at runtime, you will need to run RefreshLoadableTypes to ensure they get returned.
If you are concerned about IBotCommand implementors existing without the CommandAttribute, you can filter the ImplementingTypes, otherwise:
var botCommands = typeof(IBotCommand)
.ImplementingTypes()
.Select(t => new { Type = t, attrib = t.GetTypeInfo().GetCustomAttribute<CommandAttribute>(false) })
.Select(ta => new {
ta.Type,
TriggerString = ta.attrib.TriggerString
})
.ToDictionary(tct => tct.TriggerString, tct => tct.Type);
With an extension method for your command Types:
public static class CmdTypeExt {
public static Task ExecuteAction(this Type commandType) {
var cmdObj = (IBotCommand)Activator.CreateInstance(commandType);
return cmdObj.ExecuteAction();
}
}
You can use the Dictionary like:
var cmdString = Console.ReadLine();
if (botCommands.TryGetValue(cmdString, out var cmdType))
await cmdType.ExecuteAction();
Overall, I might suggest having a method attribute and having static methods in static classes for commands, so multiple (related?) commands can be bundled in a single class.
PS My command interpreters have help associates with each command, and categories to group commands, so perhaps some more attribute parameters and/or another IBotCommand method to return a help string.

Related

How to handle multiple identical classes in C#

I'm working with a client's API that has multiple different 'services' (around 10 so far), each one imports as its own namespace. Part of their standard API call pattern involves returning an array of error messages:
public class Error {
public String ErrorMessage {get;set}
public int errorNumber {get;set}
..etc
}
I've been trying to clean up and unify our handling of those messages. I tried to make a single function to handle them, eg:
void CheckErrors(List<Error> errors) {
if(errors != null && errors.Count() > 0)
throw new Exception(errors.First().ErrorMessage);
}
(the actual function is more complex but that gives the general idea)
However, it turns out that every one of their services has its own (identical) definition of this Error class. In C++ I could just template this function and it would work fine, or in a dynamic language it'd just work, but in C# I haven't been able to find a way to do this without making 10+ copies of the same function, each with a different namespace on the Error type.
In my own code I could just add an interface to these classes, but since it's not my code I don't think you can do that in C#? I could make a wrapper class that inherits from each of these and implements the interface, but I'm still stuck with duplicate code for every namespace/service.
Is there any cleaner way to handle this?
You could consider using a late binding solution either using reflection or dynamic. Both have the same drawback: you loose compile time type safety but if its a very isolated and contained piece of code it should be tolerable:
Reflection
void CheckErrors(List<object> errors) {
if(errors != null && errors.Count() > 0)
{
var firstError = errors.First();
throw new Exception(
firstError.GetType()
.GetProperty("ErrorMessage")
.GetValue(firstError)
.ToString()); }
Dynamic
void CheckErrors(List<dynamic> errors) {
if(errors != null && errors.Count() > 0)
throw new Exception(errors.First().ErrorMessage); }
Bear with me... you may need yet another Error class that is identical in properties to their Error class, but that you define in your namespace.
Your method CheckErrors uses your definition of Error.
Finally, you can use AutoMapper to map between their Error types and yours. This is pretty much exactly what AutoMapper is designed for. Since all your contracts are identical, the AutoMapper configuration should be trivial. Of course, you incur some runtime expense of mapping, but I think this would lead to the cleanest statically typed solution given that you can't change their interfaces.
The AutoMapper config + usage will look something like this:
//See AutoMapper docs for where to put config, it shouldn't happen on every call
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<TheirApi.Error, MyNamespace.MyErrorDefinition>();
}
var mapper = config.CreateMapper();
MyErrorDefinition myErrors = mapper.Map<List<MyErrorDefinition>>(listOfTheirErrorObjects);
CheckErrors(myErrors);
Another way is to use lambdas:
void CheckErrors<T>(IEnumerable<T> errors, Func<T,string> getMessage)
{
if (errors?.Count() > 0) throw new Exception(getMessage(errors.First()));
}
Then call it like this:
CheckErrors(errors, (e) => e.ErrorMessage);
I would define my own Error class that has a constructor that accepts any error object from your vendor and converts it. For example:
public class Error
{
public string Message { get; private set; }
public int ErrorNumber { get; private set; }
public Error(object vendorError)
{
var t = vendorError.GetType();
foreach (var source in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
foreach (var dest in typeof(Error).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
if (dest.Name != source.Name) continue;
if (dest.PropertyType != source.PropertyType) continue;
dest.SetValue(this, source.GetValue(vendorError, null));
}
}
}
}
Then when you have an error list from your third party library, you can convert it using LINQ:
var myErrorList = vendorErrorList.Select( e => new Error(e) );
And now you can access the properties per normal.
See my example on DotNetFiddle

How can I generate a constructor dependency graph for a class or list of classes?

I would like to generate a text output list that traverses my constructor dependencies for a class or list of classes. I assume I would use reflection in some way to do this? And have protection against circular dependencies.
https://stackoverflow.com/a/29704045/254257 This seems to be what I would want, but they provided no code. That question is on a similar track, but they just assume you have start with a dictionary with your dependencies already outlined as strings. So I guess how would I get that to start with.
Say I have the following:
public class UserService(IGroupService groupService, ILoggingService loggingService)
public class GroupService(IUserService userService, IRoleService roleService, ILoggingService loggingService)
public class RoleService(ILoggingService loggingService)
I would want some code to output something like this:
UserService
----GroupService
--------UserService CIRCULAR DEPENDENCY (stops going any deeper)
--------RoleService
------------LoggingService
--------LoggingService
----LoggingService
If I wanted to check dependencies on only the UserService, with the actual concrete implementation of the interfaces.
I know I can var type = typeof(UserService) as a starting point, but I've only ever worked with properties before so not sure what to do next.
I would imagine I would somehow need to get the constructor parameters, the types of those, then get the actual implementations and repeat, somehow also making sure I don't get stuck in a loop if I have any circular dependencies. Not sure how to do any of that so help would be appreciated.
Well it took some figuring out and it's probably not perfect, but for my code it worked. I started at Chetan's comment and just went down the rabbit hole. I made it a Utility:
public static class DependencyChainUtil
{
public static TypeModel GetDependencyChainForType(Type type)
{
var currentChainClassList = new List<string>();
var model = GetDependencyChainForType(type, currentChainClassList);
return model;
}
private static TypeModel GetDependencyChainForType(Type type, List<string> currentChainClassList)
{
if (type != null)
{
var model = new TypeModel() {Type = type};
if (currentChainClassList.Any(x => x == type.FullName))
{
model.IsCircularReference = true;
}
else
{
currentChainClassList.Add(type.FullName);
var constructorInfo = type.GetConstructors().Where(x => x.GetParameters().Length > 0);
foreach (var info in constructorInfo)
{
foreach (var parameterInfo in info.GetParameters())
{
var subType = parameterInfo.ParameterType;
if (subType.IsInterface)
{
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes()).Where(x => x.GetInterfaces().Contains(subType))
.ToList();
if (types.Any())
{
subType = types.FirstOrDefault();
}
}
model.ConstructorDependencies.Add(GetDependencyChainForType(subType, currentChainClassList));
}
}
currentChainClassList.Remove(type.FullName);
}
return model;
}
throw new ArgumentNullException("Parameter 'type' is null.");
}
public static string OutputTextOfDependencyChain(TypeModel model)
{
var output = "";
var depth = 0;
if (model != null)
{
output = OutputTextOfDependencyChain(model, output, depth);
}
return output;
}
private static string OutputTextOfDependencyChain(TypeModel model, string output, int depth)
{
//prepend depth markers
output += new String(Enumerable.Range(0, depth*4).SelectMany(x => "-").ToArray());
output += model.Type.Name;
output += model.IsCircularReference ? "(CYCLIC DEPENDENCY)" : null;
output += "<br/>";
depth++;
foreach (var typeModel in model.ConstructorDependencies)
{
output = OutputTextOfDependencyChain(typeModel, output, depth);
}
return output;
}
}
public class TypeModel
{
public Type Type { get; set; }
public List<TypeModel> ConstructorDependencies { get; set; }
public bool IsCircularReference { get; set; }
public TypeModel()
{
ConstructorDependencies = new List<TypeModel>();
}
}
The problem you are having stems from the fact that you are using a DI Container. Such problem is much less likely to appear when using Pure DI, since in that case the C# compiler will verify object construction, and it would be practically impossible to get such cyclic dependency.
When you use a DI Container, make sure that you use a DI Container that allows detecting cyclic dependencies and communicates a meaningful error. As a matter of fact, any of the mature DI Containers do communicate cyclic dependency errors very clearly. If your DI Container of choice does throw a stack overflow exception, please consider switching to a mature container.
Simple Injector, for instance, will throw an exception with the following message:
The configuration is invalid. Creating the instance for type IGroupService failed. The type GroupService is directly or indirectly depending on itself. The cyclic graph contains the following types: GroupService -> UserService -> GroupService.
In other words, Simple Injector shows the cyclic graph as follows:
GroupService -> UserService -> GroupService
So you don't really need object graph to be visualized, and in fact most containers won't be able to do this, because of the cyclic dependency. In case your object graph was acyclic, Simple Injector would visualize the graph as follows when you drill into the container using the Visual Studio debugger:
Or you can achieve the same by using Simple Injector's API programmatically:
var graph = container.GetRegistration(typeof(UserService)).VisualizeObjectGraph();
Which results in the following text:
UserService(
GroupService(
RoleService(
LoggingService()),
LoggingService()),
LoggingService())
Please note that your mileage might vary with other DI Containers, but again, most of the more mature libraries out their contain these types of features.

Delegated - is correct my usage of delegates?

I created a class where the main task is get data from the DB and mapping it to some object. The problem is the same class needs to map different datareader to different object. So, what I tried to do is to get out the mapping method using delegates.
Here is part of my code. See the important rows in bold.
public class GetDetails<T>
{
**public delegate void DelegateMapping(T position, IDataReader reader);**
**public DelegateMapping mappingMethod;**
public T Get(T instance)
{
//Get IDs and Add to list
_db.ExecuteReader(storedProcedure.ToString(), CommandType.StoredProcedure, reader =>
{
while ( reader.Read() )
{
**mappingMethod(instance, reader);**
}
}, parameterList.ToArray());
return instance;
}
}
And this is the class which is calling and using the "GetDetails" class
public class PositionDB : DbBase
{
public Position GetPositionDetails(string IDs)
{
GetDetails<Position> getIDs = new GetDetails<Position>(base.db);
getIDs.storedProcedure = StoredProcedure.NET_ADM_GetPositionDetails;
//Set the Delegated Method
**getIDs.mappingMethod = MappingPositionDetails;**
//Set Parameters
getIDs.parameterList.AddInParam("PositionIds", DbType.String, IDs);
//Return the PositionId Collection
return getIDs.Get(new Position());
}
**private void MappingPositionDetails(Position position, IDataReader reader)
{
position.Id = reader["CompPositionId"];
position.Description = reader["Description"];
position.ExpirationDate = reader["ExpirationDate"];
position.Title = reader["Title"];
}**
}
The code is working OK.
The questios are:
Did I use delegate correctly?
This kind of solution can cause problems in the future (performance)?
There is another better solution?
Thank you very much
Sebastian
To specifically answer your questions:
Yes, you did use delegates correctly
Yes, it can cause problems due to concurrency issues while multithreading
I think so, I detailed one possible solution below
I would propose three changes:
Move the delegate call into the method (concurrency issues, one thread could change the mapping delegate while another thread tries to access it, now trying to map a reader to completely different object than provided)
Use the already present generic Action/Func delegates, no need to define your own.
Use lambda expressions to define the mapping, no need for extra methods
Notice: 2 and 3 will need at least .net 3.5.
Employing these two proposals, your code would look like this:
public class GetDetails<T>
{
public T Get (T instance, Action<T, IDataReader> mappingMethod)
{
//Get IDs and Add to list
_db.ExecuteReader(storedProcedure.ToString(), CommandType.StoredProcedure, reader =>
{
while ( reader.Read() )
{
mappingMethod(instance, reader);
}
}, parameterList.ToArray());
return instance;
}
}
Now you can use this method in a multi-threaded environment as well.
Edit
just realized it's just part of the code. I corrected my proposal to take this into account.
Yes (There's some improvements you could make, see 3)
Not performance wise, maybe some issues in discoverability.
I would use polymorphism to eliminate the delegate completely for discoerability. Perhaps using an abstract method/class. Also depending on which .NET version you're developing for you can use lambdas and simpler types.
public Action<Position, IDataReader> Mapping { get; set; }
Then
getIDs.Mapping = (position, reader) =>
{
position.Id = reader["CompPositionId"];
position.Description = reader["Description"];
position.ExpirationDate = reader["ExpirationDate"];
position.Title = reader["Title"];
};

Property as parameter? C#

So I've got a whole bunch of options, every different page/tab can have their own local options. We'll have maybe 10-15 pages tabs open tops. I need to implement a way to show the global defaults, weather the all the tabs have consistent values. I'm working on the model/viewmodel portion of a WPF app.
I'd love to find a way that is more elegant since I'm having to cut and past roughly the same code 20+ times and just change property names. Maybe this is the problem Dynamics solve, but right now this feels both wrong and painful.
Here is an example of my current solution:
public class Foo
{
private bool fooVar1;
private bool fooVar2;
//lots of these
private decimal fooVar23;
public Foo()
{
}
public bool FooVar1
{
get;
set;
}
//you get the picture...
}
public class FooMonitor
{
private Foo defaultFoo;
private List<Foo> allFoos;
public FooMonitor(Foo DefaultFoo)
{
defaultFoo = DefaultFoo;
}
public void AddFoo(Foo newFoo)
{
allFoos.Add(newFoo);
}
public void AddFoo(Foo oldFoo)
{
allFoos.Remove(oldFoo);
}
public bool IsFooVar1Consistent
{
get
{
Foo[] tempFoos = allFoos.ToArray();
foreach (Foo tempFoo in tempFoos)
{
if (tempFoo.FooVar1 != defaultFoo.FooVar1) return false;
}
return true;
}
}
}
Or am I approaching this problem entirely incorrectly.
As I'm writing this question (After about 2000 lines of code) I'm thinking of how I read that WPF itself implements Dictionary look ups that crawl up to the parent to see if a Property is present and what the value should be.
Well, for a start you are defining both backing fields which will never be used and automatic properties. This is enough for a simple bool property:
public bool FooVar1 { get; set; }
No need for the private field. This greatly reduces the number of lines in your example.
I'd love to find a way that is more
elegant since I'm having to cut and
past roughly the same code 20+ times
and just change property names.
Code generators exist for exactly this purpose. But if you don't want to go that route, you can shorten your code to this:
return allFoos.All(foo => foo.FooVar1 == defaultFoo.FooVar1);
I'm not quite sure what the question is, but if you're looking for some way to unify the IsFoorVarXConsistent code, you could do it using reflection or by passing in an expression:
public bool IsConsistent(Func<Foo, bool> property)
{
foreach (Foo tempFoo in allFoos)
{
if (property(tempFoo) != property(defaultFoo))
return false;
}
return true;
}
Called like this:
bool is1Consistent = IsConsistent(f => f.FooVar1);
As shown this will only work for boolean properties. To extend it to other types, we can make it generic in the property type. However, in this case we cannot use != to test for inequality because not all types define a != operator. Instead we can use the .Equals method and the ! operator:
public bool IsConsistent<T>(Func<Foo, T> property)
where T : struct
{
foreach (Foo tempFoo in allFoos)
{
if (!property(tempFoo).Equals(property(defaultFoo)))
return false;
}
return true;
}
The where T : struct clause restricts this to value types like int, bool and decimal. In particular it will not work on strings. Removing the where constraint allows it to work on strings and other reference types, but creates the possibility of property(tempFoo) being null, which would cause a NullReferenceException when we called .Equals on it. So if you remove the value types constraint then you will need to add error handling for this scenario.

C# Extension methods on "members"

I have some extension methods which could be used like this:
MyType myObject;
string displayName = myObject.GetDisplayName(x => x.Property);
The problem here is that it needs an instance, even if the extension method only needs the type MyType. So if there is no instance, it needs to be called like this:
string displayName = BlahBlahUtility.GetDisplayName((MyTpe x) => x.Property);
Which is not so nice anymore.
Is there a way to write better syntax for such cases?
What I actually want to do is this (pseudo language):
string displayName = MyType.Property.GetDisplayName()
Which of course does not work with C#.
But what about something like this:
string displayName = ((MyType x) => x.Property).GetDisplayName();
This is also not possible (after a lambda, a dot is not accepted).
Any ideas?
Edit:
My "favorite syntax" MyType.Property.GetDisplayName() seems to be misleading. I don't talk about static properties here. I know that this syntax won't be possible. I just tried to show in pseudo language, what information is necessary. This would be ideal, every additional stuff is just syntactical overhead. Any working syntax that is close to this would be great.
I don't want to write a certain extension method. I want an easy, readable and compile time safe syntax, using any language feature.
Have a look at the Express and Reflect classes in the Lokad Shared Libraries. Think they may help out with what you are trying to do. Read more here:
Strongly Typed Reflection in Lokad Shared
How to Find Out Variable or Parameter Name in C#?
From your comment: "I want an easy and compile time safe syntax to get information about members".
This is a very frequently requested feature and has been discussed in the C# team's meetings for about a decade, but has never been prioritised high enough to be included.
This blog post explains why:
http://blogs.msdn.com/ericlippert/archive/2009/05/21/in-foof-we-trust-a-dialogue.aspx
So for now, you're just going to be fighting against a missing feature. Maybe you could post more information about your broader problem and see if people can suggest different approaches.
Update
Without more info about your problem this is just guesswork. But if you have a property that represents a value but also carries additional "meta" information, you could always represent that as a new type and use an "injection" step to set everything up.
Here's a suggested abstract interface to such a "meta property":
public interface IMetaProperty<TValue>
{
TValue Value { get; set; }
string DisplayName { get; }
event Action<TValue, TValue> ValueChanged;
}
The value of the property is just another sub-property, with its type defined by the user.
I've put in the display name, and also as a bonus you've got an event that fires when the value changes (so you get "observability" for free).
To have properties like this in a class, you'd declare it like this:
public class SomeClass
{
public IMetaProperty<string> FirstName { get; private set; }
public IMetaProperty<string> LastName { get; private set; }
public IMetaProperty<int> Age { get; private set; }
public SomeClass() { MetaProperty.Inject(this); }
}
Note how the setters on the properties are private. This stops anyone from accidentally setting the property itself instead of setting the Value sub-property.
So this means the class has to set up those properties so they aren't just null. It does this by calling a magic Inject method, which can work on any class:
public static class MetaProperty
{
// Make it convenient for us to fill in the meta information
private interface IMetaPropertyInit
{
string DisplayName { get; set; }
}
// Implementation of a meta-property
private class MetaPropertyImpl<TValue> : IMetaProperty<TValue>,
IMetaPropertyInit
{
private TValue _value;
public TValue Value
{
get { return _value; }
set
{
var old = _value;
_value = value;
ValueChanged(old, _value);
}
}
public string DisplayName { get; set; }
public event Action<TValue, TValue> ValueChanged = delegate { };
}
public static void Inject(object target)
{
// for each meta property...
foreach (var property in target.GetType().GetProperties()
.Where(p => p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition()
== typeof(IMetaProperty<>)))
{
// construct an implementation with the correct type
var impl = (IMetaPropertyInit)
typeof (MetaPropertyImpl<>).MakeGenericType(
property.PropertyType.GetGenericArguments()
).GetConstructor(Type.EmptyTypes).Invoke(null);
// initialize any meta info (could examine attributes...)
impl.DisplayName = property.Name;
// set the value
property.SetValue(target, impl, null);
}
}
}
It just uses reflection to find all the IMetaProperty slots hiding in the object, and fills them in with an implementation.
So now a user of SomeClass could say:
var sc = new SomeClass
{
FirstName = { Value = "Homer" },
LastName = { Value = "Simpson" },
Age = { Value = 38 },
};
Console.WriteLine(sc.FirstName.DisplayName + " = " + sc.FirstName.Value);
sc.Age.ValueChanged += (from, to) =>
Console.WriteLine("Age changed from " + from + " to " + to);
sc.Age.Value = 39;
// sc.Age = null; compiler would stop this
If you're already using an IOC container you may be able to achieve some of this without going directly to reflection.
It looks like you're trying to create a static extension method?
DateTime yesterday = DateTime.Yesterday(); // Static extension.
Instead of
DateTime yesterday = DateTime.Now.Yesterday(); // Extension on DateTime instance.
If this is what you're trying to pull off, I do not believe it is possible in the current version of C#.
It sounds like you are integrating layers a little too tightly. Normally in this type of situation I would let the presentation layer decide the implementation of GetDisplayName() instead of making it an extension of the property itself. You could create an interface called MyTypeDisplayer or whatever you fancy, and let there be multiple implementations of it not limiting you to a single display implementation.
The issue here is that one cannot get a reference to non-static methods via instance MyType.[Member]. These can only be seen through a reference to an instance of the type. You also cannot build an extension method on-top of a type declaration, only on an instance of a type - that is the extension method itself has to be defined using an instance of a type (this T x).
One can however define the expression like this to get a reference to static members:
((MyType x) => MyType.Property)
One could do something similar to string displayName = ((MyType x) => x.Property).GetDisplayName();
The first issue is guaranteeing that the compiler treats your (x=> x.Property) as an Expression rather than an action/func etc...
To do this one might need to do this:
string displayName = ((Expression<Func<PropertyType>>)((MyType x) => x.Property).GetDisplayName();
The extension method would then have to be defined like this:
public static string GetDisplayName<T>(this Expression<Func<T>> expression)
You might also have to define an extension method on top of Expression<Action>> and Expression<Action<T>> if your members are also methods.
You can do a dot after an Expression - this is where the Compile method would reside.
Appended:
I think the static call to the extension method in cases that one doesn't have an instance of the type one needs to do "reflection" on to determine a Members name would be the cleanest syntax still - this way you could still use the extension method when using an instance of a type and fall back to the static call definition => MyExtensionClass.GetDisplayName(TypeOfX x => TypeOfX.StaticMember OR x.Property/Member) when one doesn't have an instance
If you interface your properties, you could make the extension on the interface instead:
namespace Linq1
{
class Program
{
static void Main(string[] args)
{
MyType o = new MyType();
o.Property.GetDisplayName();
}
}
public class MyType
{
public IDisplayableProperty Property { get; set; }
}
public interface IDisplayableProperty
{
string GetText();
}
public class MyProperty1 : IDisplayableProperty
{
public string GetText() { return "MyProperty2"; }
}
public class MyProperty2 : IDisplayableProperty
{
public string GetText() { return "MyProperty2"; }
}
public static class Extensions
{
public static string GetDisplayName(this IDisplayableProperty o)
{
return o.GetText();
}
}
}

Categories