views:

377

answers:

6

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.

A: 

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#.

Secret Agent Man
I don't want a static extension method. I would like a easy syntax, using any language feature. I added a section to the question to explain it better.
Stefan Steinegger
+1  A: 

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.

Daniel Earwicker
Isn't there any better idea then calling the static method normally?
Stefan Steinegger
There might be, if you post more information about your broader problem. e.g. depending on the scale of what you're doing, code generation may help, or it might be overkill.
Daniel Earwicker
Updated with a different idea.
Daniel Earwicker
Thanks. Unfortunately this is not what I'm looking for. Because it must work on any class, it must not be intrusive. The meta-information that is returned by the expression is already there, somewhere, for instance in an attribute or somewhere else, it doesn't matter. I just want to exchange the call to my ugly static method (`BlahBlahUtility.GetDisplayName`) to something more readable.
Stefan Steinegger
You already know you can't "just" do that. :) What I can't understand is why you need this facility. What is the use case? In what situation is someone going to be hand-writing code that gets the display name associated with a property?
Daniel Earwicker
The display name is taken from a resource by naming convention. (This is also done by an attribute, only for data binding in the UI). Another use case is the ReflectionUtility.GetMemberName, which returns the name of the member in the expression. It really doesn't matter what it does and where the information comes from, there is something common: the argument is a lambda expression which specifies a member. The method needs to be implemented on a central place, it doesn't belong to a certain class, a typical case for an extension method. But this doesn't work here.
Stefan Steinegger
If this is for generating a UI that is bound to the properties, why does it need to be hand-coded? Why not use reflection on the object to automatically generate the UI by looping through the properties and creating suitable controls for them?
Daniel Earwicker
I don't want to use it for the UI. I need it for reporting, logging, error messages etc. etc. in the server. And there are static properties which should be localized the same way. Reflection is much to long, unreadable, error prone. The method to get it is already there, it is simple, but shouldn't be implemented every time when a display name is needed. Getting display names should be trivial. And - again, this is everything specific to display names. There are other syntactically similar cases where I don't like the syntax.
Stefan Steinegger
But my point is the same: you have a variety of classes with properties. And you want to report, log, generate error messages. You seem to be saying that someone will have to hand-write the code to format an error message that includes the display names and values of properties in the object, or something like that. Why? You can write a single function that takes any object and turns it into an error message, all controlled by attributes on the properties. There is no need to write it by hand in each case, and hence no need for a short syntax to get PropertyInfo from a property identifier.
Daniel Earwicker
I already wrote a single method that returns the data related to a single member, so it is reusable for any case. This is my BlahBlahUtility. I'm happy with the functionality of it and don't want to change anything there. I just don't like that I need to call BlahBlahUtility. The data is related to the member, so it should be easily recoverable next to the member. Thats all.
Stefan Steinegger
A: 

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.

NickLarsen
Nope, if `GetDisplayName` has an object that is the value of MyType.Property, then it doesn't have the PropertyInfo for that property. It only has the value of the property. So it cannot obtain custom attributes, for example.
Daniel Earwicker
It doesn't have anything to do with layers. DisplayName is just an example. For instance it could return data taken from attributes.
Stefan Steinegger
@Earwicker, Ohh that makes sense, I'll edit.
NickLarsen
@Stefan, the point is that you are integrating the data and how the data is being used into one location. If MyType is compiled and you know all the properties and attributes at design time, you can create another class which interprets that data in the way in which you are trying to use it.
NickLarsen
@NickLarsen: Yes, that's exactly what I'm doing. I just want to make the syntax shorter then calling static methods. I mean, `BlahBlahHelperClass.GetDisplayName((myClass x) => x)` is currently the working solution, I just want to make it shorter and more readable.
Stefan Steinegger
A: 

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

saret
Yes, I already tried casting the lambda to the expression. But this is syntactically far from ideal, so I didn't even mention it. Then it's even better to call the static method directly.
Stefan Steinegger
I agree - also found having to put the explicit Expression definition in (can't use var expression = (t => t.Property); either as the compiler probably won't see it as an Expression, but just a Func<PropertyType> definition - so you would need var to become Expression<Func<PropertyType>>)Unfortuanetly I'm not sure of a way to get the syntax to the clean state you'd like - also went the static extension method call route as it seemed cleaner...MyExtensionClass.GetDisplayName(x => TypeOfX.StaticMember), but can still use the extension method if you have an instance of the type
saret
Sorry i meant - I agree - also found having to put the explicit Expression definition in looks dirty syntax wise
saret
I've edited my answer above - see the bottom for a bit more of an answer
saret
You can create a helper method in the class you doing this that takes the Expression and will call the ExtensionMethodClass.GetDisplayName for you => GetDisplayName(Mytype x=> x.Member), public static string GetDisplayName(Expression){return ExtensionMethodClass.GetDisplayName(expression);}
saret
Calling the static method is what I'm already doing (second snippet in the question). I wan't to avoid this syntactical overhead (eg. the classname where the static method is declared in). I can't and don't want to influence MyType. This could be any type. Otherwise it would be easy.
Stefan Steinegger
A: 

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();
        }
    }
}
Dynami Le Savard
Maybe I'm missing something, but why not just rename the `GetText` method to be `GetDisplayName`, and forget about the extension method?
Daniel Earwicker
Hm, qutie right. I suppose I did that when thinking about the static entry point 'Extensions.GetDisplayName(o.Property)'
Dynami Le Savard
I can't and don't want to influence MyType. This could be any type. Otherwise it would be easy.
Stefan Steinegger
+1  A: 

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:

Svish
Thanks, interesting. I'll probably find something there.
Stefan Steinegger