Can C# nameof operator reference instance property without instance? - c#

I regularly want to get the name of an instance property of a type, when I have no instance. Currently to do this, I use the following inhouse function which interprets the Expression[Func[T, object]] parameter and returns the property name:
var str = LinqExtensions.NameOf<ClientService>(x => x.EndDate);
// Now str == "EndDate"
However it seems a shame not to use the built in nameof operator.
Unfortunately it seems that the nameof operator requires either an instance, or, to reference a static properties.
Is there a neat way to use the nameof operator instead of our in house function? For example:
nameof(ClientService.EndDate) // ClientService.EndDate not normally syntactically valid as EndDate is instance member
EDIT
I was completely wrong, the syntax nameof(ClientService.EndDate) as described actually works as is.

In the past, the documentation explicitly explained this, reading in part:
In the examples you see that you can use a type name and access an instance method name. You do not need to have an instance of the type… [emphasis mine]
This has been omitted in the current documentation. However, the examples still make this clear. Code samples such as Console.WriteLine(nameof(List<int>.Count)); // output: Count and Console.WriteLine(nameof(List<int>.Add)); // output: Add show how to use nameof to obtain the string value with the name of an instance member of a class.
I.e. you should be able to write nameof(ClientService.EndDate) and have it work, contrary to your observation in the question that this would be "not normally syntactically valid".
If you are having trouble with the syntax, please provide a good Minimal, Complete, and Verifiable code example that reliably reproduces whatever error you're getting, and provide the exact text of the error message.

Great answer by #Peter Duniho.
In case of name clashes, you can also do the following:
ClientService clientservice;
var str = nameof(clientservice.EndDate);
Not efficient, but curious enough.

Related

Under what circumstances should `object.ToString()` return null?

.Net Core defines object.ToString() as public virtual string? ToString();
This means that code such as the following provokes a CS8602 "Dereference of a possibly null reference" warning:
object t = "test";
var s = t.ToString();
Console.WriteLine(s.Length); // Warning CS8602
This is easily fixed by writing s!.Length or t.ToString()!;, but my question is:
Under what circumstances would it ever be correct to return null from an implementation of object.ToString()?
The answer would appear to be: "You should never return null from object.ToString()", which is fair enough - but that does raise another question, which is "in that case, why did Microsoft declare it as public virtual string? ToString();" ?
Aside:
Some comments below suggest that because an implementation could incorrectly return null, then the return value must be declared as string?.
If that was true, then why doesn't the same logic apply to ICloneable.Clone(), which is not declared as returning object? ?
And surely this logic would apply to every single interface method that returned a reference type? Any implementation of such a method (for example, ICustomFormatter.Format()) in theory could return null - and thus the return value should be nullable. But they are not.
Having read the link provided by DavidG, I believe the discussion in that topic answers the question to my satisfaction:
https://github.com/dotnet/coreclr/pull/23466
I can't see a reason why one would want anything.ToString() to ever return null, but who knows?
Then, I think object.ToString() is defined as returning a string? for compatibility reason: this exists since v1 of .NET and was always defined as returning a string and a string being a reference type can be null. The 'modern' declaration simply states that: there is a possibility the returned string can be null.
And do remember that this string? thing is very recent and merely metadata: even if it was typed string (as it was in older versions), implementations could still manage to return null.
In other words, brand new APIs can (and should) make use of Nullable annotations however they want, but the re-typing of existing libraries has to respect what the libraries did.
I say re-typing because it's not really typing, just annotations indicating expected behavior. It's kind of similar to the way Typescript 'annotates' Javascript code: the underlying type system is still the old one.

C# - Make a new class not part of System.Object

I have a huge code base and I recently made a change where I changed the type of a parameter from String to a custom class. On the next compile I got all the areas where the impact was, but areas where the input type was of type Object failed. for e.g.
String str = "32"
int i = Convert.ToInt32(str)
Now I have changed String to a new custom type lets say MyCustomClass I would now want following code to fail on next compile
MyCustomClass str = new MyCustomClass("32")
int i = Convert.ToInt32(str)
but it won't as Convert.ToInt32 also accepts type Object. Is there some way I can make a change in MyCustomClass that it's not considered Object anymore.
Please note: Convert.ToInt32 is only used for sample I have many more such functions, so please focus your suggestion/answer to question asked.
Override ToString() and IConvertible
You said in the comments that your intentions are to find places where your object, which had previously been treated as a string, and are now being treated as an object.
In these situations typically, the third-party code would call .ToString() on your object to get something which it can use.
So, Convert.ToInt32(str) is equivalent to Convert.ToInt32(str.ToString()).
If you implement ToString() and IConvertible to return whatever your old version of str looked like then it should continue to work in the same way as the old version.
Probably.
Sorry I know that is not the 100% perfect compile time answer you were looking for, but I think you also know very well that your MyCustomClass will always be considered object.
Possible compile time answer:
Write a tool which uses reflection to iterate over every class/struct/interface in every system/third-party DLL.
Output a load of CS files which contain all these same classes, but just throw NotImplementedException.
(T4 could help you do this)
Compile these classes into dummy.dll
Your .csproj now references only this one dummy.dll, instead of the real dlls.
Your project should compile fine against the dummy dll.
Look at your dummy.cs files and delete any use of object.
Re-compile... and suddenly you get a load of compile time errors showing you anywhere you are using an object.
Impliment an implicit cast from MyCustomClass to String.
public static implicit operator string(MyCustomClass str)
{
return "Legacy respresentation of str";
}
This allows the complier the choice of choosing ToInt32(Object) or ToInt32(String), and I bet it favours the later.
This way all your existing function calls will remain the same so you wont have to be concerned about third party implentation details.
(Sorry, I am not at a computer right now so I can`t test that my assumtion is correct. If you do test this, be sure to consider extension methods, as they can affect the conpilers desision making in unexpected ways)

Why does retrieving the property name on a anonymous type give the following result?

A junior co-worker of mine managed to write very scary, scary code.
printJob.Type = item[LocalFunctions.GetName(new { printJob.Type })].ToString();
public static string GetName<T>(T item) where T : class
{
try
{
return typeof(T).GetProperties()[0].Name;
}
catch (Exception ex)
{
return null;
}
}
What is you gues what will GetName will output? It will output "Type"!
I just don't get how this is possible. My first thought is that MS will create an anonymous type with property that has the same name as the property from which the value came from (compiler magic?). As this cannot possibly be a supported feature, I advised my junior co-worker to not use things he cannot understand.
But that leaves the question open: How is this possible?
Anonymous types infer property names unless they are specified:
If you do not specify member names in the anonymous type, the compiler
gives the anonymous type members the same name as the property being
used to initialize them.
http://msdn.microsoft.com/en-us/library/bb397696.aspx
The compiler then infers the type for the generic at compile time - so typeof(T) works. It is fully supported, even if the code is fragile. What happens when someone refactors the name of the property?
I'd also say it's inadvisable to advise people on topics you don't have an answer to yourself - this is the source of many a www.thedailywtf.com article ;-)
Personally I'd still remove this in favour of more robust code, instead of assuming the property name is always going to be the same.
That's what the compiler (not MS) does when creating anonymous types. It uses The type, name and order of the supplied parameters to construct a new type. This is fully supported and intended to be that way, so there's no reason not to use it.
The compiler has all the information available to do this. It sees what name and type the properties you used to initialize it have (such as printJob.Type) and can use that information to generate the anonymous type for you.
See here for more information:
http://msdn.microsoft.com/en-us/library/bb397696.aspx

Delegate as first param to an Extension Method

Ladies and Gents,
I recently tried this experiment:
static class TryParseExtensions
{
public delegate bool TryParseMethod<T>(string s, out T maybeValue);
public static T? OrNull<T>(this TryParseMethod<T> tryParser, string s) where T:struct
{
T result;
return tryParser(s, out result) ? (T?)result : null;
}
}
// compiler error "'int.TryParse(string, out int)' is a 'method', which is not valid in the given context"
var result = int.TryParse.OrNull("1"); // int.TryParse.OrNull<int>("1"); doesnt work either
// compiler error: type cannot be infered....why?
var result2 = TryParseExtensions.OrNull(int.TryParse, "2");
// works as expected
var result3 = TryParseExtensions.OrNull<int>(int.TryParse, "3");
var result4 = ((TryParseExtensions.TryParseMethod<int>)int.TryParse).OrNull("4");
I am wondering two things:
Why can the compiler not infer the "int" type parameter?
Do I understand correctly that extensions methods do not get discovered on Delegate types, as I guess they arent really of that type (but are a "Method") that only happen to match the delegates signature? As such a cast solves this. Would it be infeasable to enable scenario 1 to work (not this one specifically of course, but in general)? I guess from a language/compiler perspective and would it actually be useful, or am I just (attempting to) wildly abusing things here?
Looking forward to some insights. Thnx
You have a number of questions here. (In the future I would recommend that when you have multiple questions, split them up into multiple questions rather than one posting with several questions in it; you'll probably get better responses.)
Why can the compiler not infer the "int" type parameter in:
TryParseExtensions.OrNull(int.TryParse, "2");
Good question. Rather than answer that here, I refer you to my 2007 article which explains why this did not work in C# 3.0:
http://blogs.msdn.com/b/ericlippert/archive/2007/11/05/c-3-0-return-type-inference-does-not-work-on-member-groups.aspx
Summing up: fundamentally there is a chicken-and-egg problem here. We must do overload resolution on int.TryParse to determine which overload of TryParse is the intended one (or, if none of them work, what the error is.) Overload resolution always tries to infer from arguments. In this case though, it is precisely the type of the argument that we are attempting to infer.
We could come up with a new overload resolution algorithm that says "well, if there's only one method in the method group then pick that one even if we don't know what the arguments are", but that seems weak. It seems like a bad idea to special-case method groups that have only one method in them because that then penalizes you for adding new overloads; it can suddenly be a breaking change.
As you can see from the comments to that article, we got a lot of good feedback on it. The best feedback was got was basically "well, suppose type inference has already worked out the types of all the argument and it is the return type that we are attempting to infer; in that case you could do overload resolution". That analysis is correct, and changes to that effect went into C# 4. I talked about that a bit more here:
http://blogs.msdn.com/b/ericlippert/archive/2008/05/28/method-type-inference-changes-part-zero.aspx
Do I understand correctly that extensions methods do not get discovered on delegate types, as I guess they arent really of that type (but are a "Method") that only happen to match the delegates signature?
Your terminology is a bit off, but your idea is correct. We do not discover extension methods when the "receiver" is a method group. More generally, we do not discover extension methods when the receiver is something that lacks its own type, but rather takes on a type based on its context: method groups, lambdas, anonymous methods and the null literal all have this property. It would be really bizarre to say null.Whatever() and have that call an extension method on String, or even weirder, (x=>x+1).Whatever() and have that call an extension method on Func<int, int>.
The line of the spec which describes this behaviour is :
An implicit identity, reference or boxing conversion [must exist] from [the receiver expression] to the type of the first parameter [...].
Conversions on method groups are not identity, reference or boxing conversions; they are method group conversions.
Would it be infeasable to enable scenario 1 to work (not this one specifically of course, but in general)? I guess from a language/compiler perspective and would it actually be useful, or am I just (attempting to) wildly abusing things here?
It is not infeasible. We've got a pretty smart team here and there's no theoretical reason why it is impossible to do so. It just doesn't seem to us like a feature that adds more value to the language than the cost of the additional complexity.
There are times when it would be useful. For example, I'd like to be able to do this; suppose I have a static Func<A, R> Memoize<A, R>(this Func<A, R> f) {...}:
var fib = (n=>n<2?1:fib(n-1)+fib(n-2)).Memoize();
Instead of what you have to write today, which is:
Func<int, int> fib = null;
fib = n=>n<2?1:fib(n-1)+fib(n-2);
fib = fib.Memoize();
But frankly, the additional complexity the proposed feature adds to the language is not paid for by the small benefit in making the code above less verbose.
The reason for the first error:
int.TryParse is a method group, not an object instance of any type. Extension methods can only be called on object instances. That's the same reason why the following code is invalid:
var s = int.TryParse;
This is also the reason why the type can't be inferred in the second example: int.TryParse is a method group and not of type TryParseMethod<int>.
I suggest, you use approach three and shorten the name of that extension class. I don't think there is any better way to do it.
Note that your code works if you first declare :
TryParseExtensions.TryParseMethod<int> tryParser = int.TryParse;
and then use tryParser where you used int.TryParse.
The problem is that the compiler doesn't know which overload of int.Parse you're speaking about. So it cannot completely infer it : are you speaking about TryParse(String, Int32) or TryParse(String, NumberStyles, IFormatProvider, Int32) ? The compiler can't guess and won't arbitrarily decide for you (fortunately !).
But your delegate type makes clear which overload you're interested in. That's why assigning tryParser is not a problem. You're not speaking anymore of a "method group" but of a well identified method signature inside this group of methods called int.TryParse.

DefaultMemberAttribute - what does it do?

I've already read the MSDN article about it. It seems internally it is the way c# sets which is the function that is going to work as indexer(am I right?). Now, I've seen the following example:
[DefaultMemberAttribute("Main")]
public class Program {
public static void Main() {
...
}
}
Now, I don't get it what it means.
Thanks all. But I still can't get its usefulness, apart from the indexer thing. When are we going to call InvokeMember?
No, the DefaultMemberAttribute is used by languages such as VB.NET to find out the member that is acted on by default if no member is referenced from an object, i.e. the member invoked by InvokeMember. This is often used in conjunction with indexers, as you noted, but it is not used by C# directly (unless you use InvokeMember explicitly).
However, for the benefit of other .NET languages, C# does emit the DefaultMemberAttribute for the indexer of a class (if it has one), as indicated by MSDN:
The C# compiler emits the
DefaultMemberAttribute on any type
containing an indexer. In C# it is an
error to manually attribute a type
with the DefaultMemberAttribute if the
type also declares an indexer.
I think MSDN confuses things by referring to indexers a lot in the remarks but then giving an example that does not use an indexer. To clarify, the default member can be anything, but C# gives special behavior for indexers by emitting the attribute for you (if an indexer exists) to the exception of all other use cases.
I personally have never used it, but as far as I can tell you are defining the default method to be invoked when calling InvokeMember. So, using the code snippet you provided if I was to say:
Program prog = new Program();
typeof(Program).InvokeMember("", null, null, prog, null);
Because I left the first argument empty of the InvokeMember call it would use the attribute to determine what the default member is of your class, in your case it is Main.
The DefaultMemberAttribute attribute defines the default member to be called on a when InvokeMember is called with an empty string as the first argument.
If you read the MSDN docs for InvokeMember, it explicitly says:
Parameters
name
Type: System.String
The String containing the name of the constructor, method, property, or field member to invoke.
-or-
An empty string ("") to invoke the default member.
The default member will be the one declared by the DefaultMemberAttribute attribute.

Categories