Extending Enums with Custom Attributes and const values issue - c#

I implemented Custom Attributes for enum using this article, everything is fine with hard coding values, but I need to pass the parameters in run time, for example:
enum MyItems{
[CustomEnumAttribute("Products", "en-US", Config.Products)]
Products
}
The Config.Products (bool value) is the problem, the error is:
An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
Is there any way to fix this?
Update
The enum (MyItems in this case) have 20 items, each item must have that custom attribute, then I want to generate menu from the Enum's items, depended on Culture I getting the matched title, also depended on Config, I decided to show/hide the item from the menu (in fact if Config.X == false, I don't add the item to the menu)
Also, for Config, I have another system and I wanna sync that system with the menu, that is the reason that I wanna get the Config.X in run-time.
Thanks!

No way to fix this, it's a limitation of attributes.
You can use static readonly fields in case you need a fixed set of objects with behaviour:
public class MyItems
{
public string Name { get; private set; }
public string Locale { get; private set; }
readonly Func<OtherThing> factory;
public static readonly MyItems Products = new MyItems("Products", "en-US", () => Config.Products);
public static readonly MyItems Food = new MyItems("Food", "en-GB", () => Config.FishAndChips);
private MyItems(string name, string locale, Func<OtherThing> factory)
{
this.Name = name;
this.Locale = locale;
this.factory = factory;
}
public OtherThing GetOtherThing() {
return factory();
}
}
See another answer for a more complete example:
C# vs Java Enum (for those new to C#)

You could create an extension method
public string GetConfigValue(this MyItems myItem)
{
return Config.GetType().GetProperty(myItem.ToString()).GetValue(Config, null);
}
This uses reflection to access the relevant property on the Config object. In the example you give, if myItem = Products then you can call
myItem.GetConfigValue()
And it should return the value of Config.Products
Related SO Questions:
Dynamic Evaluation
Enum Name
Based on your update, I'd suggest this even more. Attributes must be constant values at compile time (hence the error you're getting). Even if you do not go the extension method route, you absolutely need some sort of method.

Related

C# 9 require property set at construction without explicit constructor [duplicate]

I have requirement in a custom class where I want to make one of my properties required.
How can I make the following property required?
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
If you mean "the user must specify a value", then force it via the constructor:
public YourType(string documentType) {
DocumentType = documentType; // TODO validation; can it be null? blank?
}
public string DocumentType {get;private set;}
Now you can't create an instance without specifying the document type, and it can't be removed after that time. You could also allow the set but validate:
public YourType(string documentType) {
DocumentType = documentType;
}
private string documentType;
public string DocumentType {
get { return documentType; }
set {
// TODO: validate
documentType = value;
}
}
.NET 7 or newer
Syntax
public class MyClass
{
public required string Name { get; init; }
}
new MyClass(); // illegal
new MyClass { Name = "Me" }; // works fine
Remarks
The required properties must declare a setter (either init or set).
Access modifiers on properties or setters cannot be less visible than their containing type, as they would make impossible to initialize the class in some cases.
public class MyClass
{
internal required string Name { get; set; } // illegal
}
Documentation
Official documentation here
Feature demo here
.NET 6 or older
See this answer
If you mean you want it always to have been given a value by the client code, then your best bet is to require it as a parameter in the constructor:
class SomeClass
{
private string _documentType;
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
public SomeClass(string documentType)
{
DocumentType = documentType;
}
}
You can do your validation – if you need it – either in the property's set accessor body or in the constructor.
With the release of .NET 7 and C# 11 in November 2022 you can now use the required modifier this way:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
public int Age { get; set; }
}
And when you don't have the required properties it will throw an error when you try to initialize an object.
For more information refer to:
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-11#required-members
https://learn.microsoft.com/en-us/dotnet/csharp/properties#init-only
Add a required attribute to the property
Required(ErrorMessage = "DocumentTypeis required.")]
public string DocumentType
{
get
{
return _documentType;
}
set
{
_documentType = value;
}
}
For custom attribute detail Click Here
I used an other solution, not exactly what you want, but worked for me fine because I declare the object first and based on specific situation I have different values. I didnt want to use the constructor because I then had to use dummy data.
My solution was to create Private Sets on the class (public get) and you can only set the values on the object by methods. For example:
public void SetObject(string mandatory, string mandatory2, string optional = "", string optional2 = "")
This one liner works in C# 9:
public record Document(string DocumentType);
new Document(); // compiler error
new Document("csv"); // correct way to construct with required parameter
This explains how it works. In the above code, Document is the name of the class or "record". That first line of code actually defines an entire class. In addition to this solution essentially making a required DocumentType property (required by an auto implemented constructor), because it uses records, there are additional implications. So this may not always be an appropriate solution, and the C# 11 required keyword will still come in handy at times. Just using record types doesn't automatically make properties required. The above code is a special syntax way of using records that essentially has this effect as well as making the property init only and causes a deconstructor to be automatically implemented.
A better example would be using an int property instead of a string since a string could still be empty. Unfortunately I don't know of any good way to do extra validation within the record to make sure the string is not empty or an int is in range, etc. You would have to go deeper down the TOP (type driven development) rabbit hole, which may not be a bad thing. You could create your own type that doesn't allow empty strings or integers outside your accepted range. Unfortunately such an approach would lead to runtime discovery of invalid input instead of compile time. There might be a better way using static analysis and metadata, but I've been away from C# for too long to know anything about that.

How to create a centralized provider of Expression<Func<T, object>> with different types?

I wrote sorting logic for ASP.NET Core 2.2 web application. My concept is to define a dictionary holding sort order rules. The dictionary has string keys. Every rule is associated to entity type. Also there is a possibility of retrieving a sort order rule for a particular type of entity by a string key.
The sorting logic I wrote does not order any collection, it only stores and provides information required for sorting. Every sort order rule has:
an Expression<Func<T, object>>;
a bool flag describing sorting way (ascending/descending);
a bool flag indicating whether particular sort order rule is a default one.
I defined that data in ISortOrderRule<T> interface:
public interface ISortOrderRule<T>
{
Expression<Func<T, object>> Expression { get; }
bool IsDescending { get; }
bool IsDefault { get; }
}
with default implementation in SortOrderRule<T> class:
public class SortOrderRule<T> : ISortOrderRule<T>
{
public Expression<Func<T, object>> Expression { get; set; }
public bool IsDefault { get; set; }
public bool IsDescending { get; set; }
}
The expression can be used for example as argument for OrderBy() LINQ method. IsDefault flag can be used in fallback mechanism to default sort order if no other was found.
Now, in order to create sort order rules for particular entity I created a generic interface ISortOrderCollection<T> where sort order rules can be stored in an underlaying dictionary:
public interface ISortOrderCollection<T> :
IReadOnlyDictionary<string, ISortOrderRule<T>>,
IReadOnlyCollection<KeyValuePair<string, ISortOrderRule<T>>>,
IEnumerable<KeyValuePair<string, ISortOrderRule<T>>>,
IEnumerable
{
}
Readonly because I wanted it to be closed for outside world but open to classes deriving from SortOrderCollectionBase<T>:
public abstract class SortOrderCollectionBase<T> : ISortOrderCollection<T>
{
private readonly IDictionary<string, ISortOrderRule<T>> _rules;
public SortOrderCollectionBase()
{
_rules = new Dictionary<string, ISortOrderRule<T>>();
}
protected void AddSortOrderRule(string key, ISortOrderRule<T> sortOrderRule)
{
// Tweak over the key, add prefix or suffix depending on sorting way
// So sort order rules for the same property but with opposite
// sorting way can be distinguished.
var sortRuleKey = BuildSortOrderRuleKey(key, sortOrderRule);
_rules.Add(sortRuleKey, sortOrderRule);
}
// Implementations of interface members removed for brevity.
}
Now I can add some sort order rules for Level entity:
public class LevelSortOrderCollection : SortOrderCollectionBase<Level>
{
public LevelSortOrderCollection()
{
AddSortOrderRule(nameof(Level.Position), new SortOrderRule<Level>
{
Expression = (level) => level.Position,
IsDefault = true,
});
AddSortOrderRule(nameof(Level.Position), new SortOrderRule<Level>
{
Expression = (level) => level.Position,
IsDescending = true,
});
}
}
Level model:
public class Level
{
public int Id { get; set; }
public int Position { get; set; }
}
Types implementing ISortOrderCollection<T> are registered in Startup in ConfigureServices() method:
services.AddScoped<ISortOrderCollection<Level>, LevelSortOrderCollection>();
// ...
And finally I can use the sort order collection in a controller:
public class LevelsController : Controller
{
private readonly IRepository<Level> _levelsRepository;
private readonly ISortOrderCollection<Level> _levelSortOrder;
public LevelsController(
IRepository<Level> levelsRepository,
ISortOrderCollection<Level> levelSortOrder)
{
_levelsRepository = levelsRepository;
_levelSortOrder = levelSortOrder;
}
public async Task<IActionResult> Index(string sort)
{
var sortOrder = _levelSortOrder[sort];
var result = await _levelsRepository.GetPageAsync(sortOrder.Expression);
return View(result);
}
}
GetPageAsync() of IRepository<Level> accepts an expression which later is used to order records with OrderBy().
Note, that I deliberately cut out some code IMO not bringing anything worth putting here like null checks, validation, controller/repository logic choosing whether to call OrderBy() or OrderByDescending() and fallbacking to default sort order. If you feel that you need to see more, let me know in comments.
Question
How to create a centralized sort order rule provider with access to many sort order collections for multiple entities? Instead of directly injecting a sort order collection for a particular entity type inside a controller, I'd like to be able to inject a general use sort order provider, like this:
private readonly IRepository<Level> _levelsRepository;
private readonly ISortOrderProvider _sortOrderProvider;
public LevelsController(
IRepository<Level> levelsRepository,
ISortOrderProvider sortOrderProvider)
{
_levelsRepository = levelsRepository;
_sortOrderProvider = sortOrderProvider;
}
and then I'd call some kind of method with type parameter:
var sortOrder = _provider.GetSortOrderRule<Level>("Position");
which would try to find sort order rule for type of entity passed in a type parameter with a matching string key.
Final note
I'm aware all this is pretty complex, so there is a good chance to have a completely different way to achieve what I'm trying to do. I'm not closed-minded to that kind of answers.
First of all, I would recommend you not to implement all these dictionary interface in your ISortOrderCollection<T>. While it may make sense to you to make that collection an actual collection, there isn’t actually a lot benefit for that: After all, you mostly add items or retrieve items by their key. You don’t actually need all the other things that these interfaces will require you to implement. Instead, use a small interface that only covers what you actually need and use composition to implement this. This also makes it easier to test.
So you are saying that you want a single provider that keeps all sort order expressions for all your types. Start by thinking how you would want to use that, and build an interface that offers the necessary APIs:
public interface ISortOrderProvider
{
void Add<T>(string name, ISortOrderRule<T> sortOrderRule);
ISortOrderRule<T> Get<T>(string name);
ISortOrderRule<T> GetDefault<T>();
}
Okay, so if you look at that, you will notice that you effectively have two keys now: The sort order key and the type. So use both as a key in a dictionary.
Now, for the default rule, there are a few strategies: You could have a separate dictionary that just stores the default rule for each type; you could also iterate through all rules, looking for the default, when you request it; or you could store the default rule under a common name that makes it possible to look up that directly. I’ll opt for the latter idea.
So here is a straightforward example implementation:
public class SortOrderProvider : ISortOrderProvider
{
private const string DefaultKey = "__default";
private readonly Dictionary<(Type, string), object> _rules = new Dictionary<(System.Type, string), object>();
public void Add<T>(string name, ISortOrderRule<T> sortOrderRule)
{
_rules[(typeof(T), name)] = sortOrderRule;
if (sortOrderRule.IsDefault)
_rules[(typeof(T), DefaultKey)] = sortOrderRule;
}
public ISortOrderRule<T> Get<T>(string name)
{
if (_rules.TryGetValue((typeof(T), name), out var value))
return (ISortOrderRule<T>)value;
return GetDefault<T>();
}
public ISortOrderRule<T> GetDefault<T>()
{
if (_rules.TryGetValue((typeof(T), DefaultKey), out var value))
return (ISortOrderRule<T>)value;
else
return null;
}
}

c# rules editor, advice or suggestions

I want to provide predefined filters for displaying search results. The filter is more or less stored as an expression tree and can be constructed using a rule editor.
I want to provide the user with an editor, select a property, select the operator and allow the user to provide or select a value to compare with.
[dropdown with properties = PriorityId] [dropdown with operators = Equals] [dropdown with values = IList()]
The challenge is that the user needs to get a list of values to select from and I am figuring out how to
I have thought about the following approach, and I would like to get your input on this.
Decorate the property with an attribute
The attribute maps a class responsible for returning possible values
The mapping class implements an interface
When selecting the property from the rule editor I can execute an ajax call to a supporting controller to get the values back. In this controller I can invoke the mapping class via reflection to return the values.
namespace Tickets.Data.Model
{
public class Ticket : BaseModel
{
[RuleEditorCollectionMapping(typeof(GetPriorities))]
public string PriorityId { get; set; }
}
}
public class RuleEditorCollectionMappingAttribute : Attribute
{
private Type classType;
public RuleEditorCollectionMappingAttribute(Type classType)
{
this.classType = classType;
}
}
public interface IRuleEditorCollectionMapping{}
public class GetPriorities : IRuleEditorCollectionMapping
{
public static IList<TicketPriority> GetValues()
{
// query logic to build a list with values to be used in the rules editor when selecting PriorityId
return new List<TicketPriority>();
}
}
Questions:
Is my approach a viable one? More or less a sanity check so I don't take the wrong turn.
If not, do you have any other suggestions or guidance from experience to approach this situation?

Validating a large dictionary of set strings with user input

I have a profile form that has a lot of user selections and I am sort of stumped on a good approach to validate what the user enters, when passing validation mapping those values to object properties.
For example I have a dictionary
public static Dictionary<string, string> objProfileSelections = new Dictionary<string, string>();
public static string MySelections(string key)
{
objProfileSelections.Add("1", "No Answer");
objProfileSelections.Add("3", "Less Than $25,000");
objProfileSelections.Add("5", "$35,000 to $50,000");
objProfileSelections.Add("7", "$50,000 to $75,000");
objProfileSelections.Add("9", "$75,000 to $100,000");
objProfileSelections.Add("11", "$100,000 to $150,000");
objProfileSelections.Add("13", "$150,000+");
objProfileSelections.Add("2", "No Answer");
objProfileSelections.Add("4", "Less Than $25,000");
objProfileSelections.Add("6", "$35,000 to $50,000");
objProfileSelections.Add("8", "$50,000 to $75,000");
objProfileSelections.Add("10", "$75,000 to $100,000");
objProfileSelections.Add("12", "$100,000 to $150,000");
objProfileSelections.Add("14", "$150,000+");
string item;
objProfileSelections.TryGetValue(key, out item);
return item;
}
Id like to pass in a list of key strings from the user and pass those items to populate an object. The issue is I don't know how to code it so it know which property to go to, I looked at reflection, but I couldn't find any examples that have a set dictionary of values that map to property names.
To make a bit more clear, when a user makes a selection it passes as a parameter in the dictionary, and the dictionary outputs the items. From key 1 comes value No Answer. If the user selected all the check boxes it would be value - (1,3,5,7,9,11,13). I need to extract those values when there is a matching key to a matching property. For example if the user clicks 1,5 but leaves the rest unchecked, how do I know which selections the user made? How do I get the program to know which property to populate based on the results?
*edit
some properties I would like it mapped to
public string MyAnnualIncome{ get; set; }
public List<string> InterestAnnualIncome{ get; set; }
So the first property would be taking one value, and the second property would be taking multiple values.
When a key matches a value comes out the dictionary, I would need the odd values going to MyAnnualIncome and the even values going to InterestAnnualIncome.
so no one is confused odd and even keys are set up for a purpose, odd numbers belonging to a certain group of properties and the even ones belonging to another based on the html selections (even being my selections, odd being what I am interested in)
*Update
Is there a way I can possibly use the keys like 1,3,5 and pass that into a list using the except extension method. Then take the results and use a method to convert the values from enumerated data types to strings?
Hopefully I understood your question.
I would add a small helper class (this is a solution which doesn't use reflection, but uses delegates instead):
public class PropertyModifier
{
private string text;
private Func<string> modifier;
public PropertyModifier(Func<string> modifier)
{
this.modifier = modifier;
}
public PropertyModifier With(string text)
{
PropertyModifier newModifier = new PropertyModifier(modifier);
newModifier.text = text;
return newModifier;
}
public void Modify()
{
modifier(Text);
}
}
Then I would rewrite your code and have the dictionary map to this class instead to string:
public static Dictionary<string, PropertyModifier> objProfileSelections = new Dictionary<string, PropertyModifier>();
public static MyUserProfile Profile; //Assuming this is the object you want to modify
public static string MySelections(string key)
{
PropertyModifier myIncome = new PropertyModifier(text => Profile.MyAnnualIncome = text);
PropertyModifier interestIncome = new PropertyModifier(text => Profile.InterestAnnualIncome.Add(text));
objProfileSelections.Add("1", myIncome.With("No Answer"));
objProfileSelections.Add("3", myIncome.With("Less Than $25,000"));
...
objProfileSelections.Add("2", interestIncome.With("No Answer"));
objProfileSelections.Add("4", interestIncome.With("Less Than $25,000"));
...
}
Then, when processing the user's selection, get the mapped PropertyModifier from the dictionary and call its Modify method.
I tried in this code to illustrate how you can modify the properties of the different classes that may compose a profile. Modifications are done by reflection only, i.e. just providing the class name, the property name that will vary in each class and the string value to be assigned to the property.
Not sure that it fits your expectations :(
Profile profile = new Profile() ;
profile.SetPropertyValue("hair","color","brown") ;
internal class Profile()
{
private Hair hair_ = new Hair();
private Job job_ = new Job ();
internal Hair hair { get { return hair_ ; } }
internal Job job { get { return job_ ; } }
private void SetPropertyValue(string profileItemName, string ItemPropertyName, string value)
{ // it is assumed that the different items (hair or job) of the Profile are accessible
// with a a property
// first find the Item object, i.e. hair or job
object itemObj = this.GetType().GetProperty(profileItemName).GetValue(this,null);
// assign to Item property the input value, e.g. hair.color=Brown
itemObj.GetType().GetProperty(ItemPropertyName).SetValue(itemObj, value, null);
}
}
internal class Hair()
{
private string color_ ;
private string style_ ;
internal string color { get { return color_ ; } set {color_ = value ; } }
internal string style { get { return style_ ; } set {style_ = value ; } }
}

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