c# custom attribute for a method parameter - how it works? - c#

I would like to understand how this particular case works. Here is the shot from msdn article where INotifyPropertyChanged interface is explained (https://msdn.microsoft.com/query/dev12.query?appId=Dev12IDEF1&l=EN-US&k=k%28System.ComponentModel.INotifyPropertyChanged%29;k%28TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5%29;k%28DevLang-csharp%29&rd=true)
As it's said in marked lines there is a way of intercepting method call to substitute a value instead of what is actual goes as a parameter?
I would like to get an idea of what the code to do this looks like. I know how to work with attributes set for properties and other class members but this use case is not clear for me.
Thanks.

It seems to be a feature implemented in the compiler: it knows about this special attribute and it substitutes the name of the caller into the optional argument when it has its default value.
If you want you can check the Roslyn implementation. Although it is not always very straightforward to navigate there seems to be something here in the GetDefaultParameterValue function (starting at line 844, at least in the current revision as of the time of writing -- 0db946b):
if the optional parameter is annotated with <see cref="CallerLineNumberAttribute"/>, <see cref="CallerFilePathAttribute"/> or <see cref="CallerMemberNameAttribute"/>, and there is no explicit argument corresponding to it, we will provide caller information as a value of this parameter.
At line 912 there is an else if clause that handles this case (the if and else if clauses before that handle the similar new features CallerLineNumberAttribute and CallerFilePathAttribute):
...
else if (parameter.IsCallerMemberName && ((callerSourceLocation = GetCallerLocation(syntax, enableCallerInfo)) != null))
...
which is eventually used to bind the parameter:
BoundExpression memberNameLiteral = MakeLiteral(syntax, ConstantValue.Create(memberName), _compilation.GetSpecialType(SpecialType.System_String));
defaultValue = MakeConversion(memberNameLiteral, parameterType, false);

Related

Where does System.Runtime.CompilerService.Dynamic attribute comes from and are we supposed to use it?

Today I was looking at some code of Nancy and since I like to explore the code I noticed following thing.
While navigating in VS2017 I went to NancyModule I saw the code from the metadata the following:
public virtual void Delete(string path, [Dynamic(new[] { false, true, false })] Func action, Func condition = null, string name = null);`
Now I don't know what this attribute does so I immediately went to msdn.
Parameters
transformFlags:
Type: System.Boolean[]
Specifies, in a prefix traversal of a type's construction, which Object occurrences are meant to be treated as a dynamically dispatched type.
Remarks
For instance, if C is a generic type with two type parameters, a use of the constructed type C might be intended to treat the first type argument dynamically and the second typically, in which case the appropriate attribute specification should use a transformFlags value of { false, true, false }.
After that I realized that in Nancy's code there is no such attribute applied so I thought myself "Okay, so maybe the compiler adds it." However, after decompiling this assembly with dnSpy, ilSpy I don't see such attribute at all.
So bottom line questions are:
Is this attribute intended for usage by users of .NET framework or it is only the compiler applying it (given the fact its namespace)?
What does those flags mean in its constructor? I am not sure I understand what is prefix traversal of a type's construction.
The dynamic keyword in C# does not have a dedicated type in the metadata and at runtime, it is simply object. When you add a reference to the assembly then you like to see it back as dynamic. So does the C# compiler, necessary so it can auto-generate the binder code. The [Dynamic] attribute ensures that happens.
A decompiler would do the same thing so it doesn't have to show you this attribute either. Whatever tool you used to browse the metadata wasn't that smooth about it and revealed the detail.
The C# compiler emits the attribute automatically. Nothing you have to do yourself.

Const String From Settings

I would like to set a const string from Settings.
In case I would like to change in the future the program language, it is quite easy;
Just have to modify the appropriate settings!
When trying this:
private const string constString =
"-&" + Properties.Settings.Default.constStringText;
I get this error:
The property or indexer 'Properties.Settings.Default'
cannot be used in this context because it lacks the get accessor.
Any idea?
Since you intend to use this as the default value for an optional method argument, that is:
public void Foo(string something = constString)
{
//do something
}
This constString must be a compile-time constant. From the MSDN page for "Named and Optional Arguments":
A default value must be one of the following types of expressions:
a constant expression;
an expression of the form new ValType(), where ValType is a value type, such as an enum or a struct;
an expression of the form default(ValType), where ValType is a value type.
As such, there really is no way to read a value from a configuration file at runtime then use it for an optional argument.
One workaround would be to instead declare your constString as a readonly field:
private readonly string constString =
"-&" + Properties.Settings.Default.constStringText;
Then make your optional argument required and create a wrapping overload for your method that doesn't take that parameter. That overload in turn calls the old method with the default value resolved at runtime:
public void Foo(string something) //no longer optional
{
//do something
}
public void Foo()
{
Foo(constString); //calls the other overload with the default value
}
This error is in 99% of cases related to a wrong namespace.
You've probably generated some class in which you are using Properties.Settings.Default
Solution: check namespace in that class file. It must be the same as the name of the tag in App.config (Web.config) where that particular setting is stored.
While Chris Sinclair’s answer (a const member must have value type and be evaluable at compile-time, so use readonly) is correct, I should like to explain these restrictions and answer the implicit question what the compiler message means, albeit with the disappointing remark that seems to be simply an error in the compiler.
The error message
The property or indexer 'Properties.Settings.Default' cannot be used in this context because it lacks the get accessor.
This message suggests that the expression Properties.Settings.Default could be made acceptable by adding a getter (and maybe something else) — as far as I know, that is simply wrong. After all, on the one hand, as the asker assured us1, there was a getter, and on the other, as Chris explains, the reason the expression is invalid is that is not evaluable at compile-time, and never can be, given that it depends on the run-time configuration.
Presumably this message is intended for other situations, and has been used here by mistake.
1 I have also seen this, in MSVS 2013, when a default parameter value referred to a property which did have a getter – but at least it also reported “Default parameter value for '<parname>' must be a compile-time constant”.
The restriction to value types
The restriction of const members and default parameter values to value types (as at the C# 5.0 Language Specification, 2012) appears to be not entirely inevitable, but an understandable consequence of other language design decisions.
A reference type can have a constructor evaluable at compile-time, but this is not supported ; perhaps this is because the language offers no way of indicating that a referenced object is immutable, nor even the concept of immutability of reference type objects. (Remember: an immutable reference to an object need not be a reference to an immutable object!)
Delegate values referring to static methods can also be considered fully determined at compile-time, as would those bound to immutable objects, were that concept supported.
Immutable arrays as constant values sound fairly easy to support.
Constant members¹ and (I believe)² default parameter values are specified to be part of the ‘interface’ of the class, in the sense that their values are to be determined at compile time and hard-coded into generated code using that class.
Resolution of the problem
You can use ( static ) readonly constString instead of const constString, to make clear that while the value will not change, it is not determined until run-time, at class or object initialisation (as in Chris’s answer).
If you want to use the expression as a default value for an optional parameter, it must be a true compile-time constant, leaving you two possibilities:
Declare an overload, as in Chris’s answer, e.g.:
Foo() { Foo(Default); } Foo(string s) { Bar(s); }.
This will often be the simpler solution, but could clutter your code and interface if you have many such parameters and thus many overloads, all with documentation comments.
Use null as a convention for the default, and interpret that in your method:
Foo(string s = null) { Bar(s != null ? s : Default); }.
This obviously only works if null is not a supported parameter to Foo(string) and should definitely be clarified in documentation comments.
Maybe: apply the Optional attribute, as in this question: behaviour of Optional attribute:
Foo([Optional] string s) { Bar(etc.?); } .
I have not used or studied this – the documentation seemed rather sparse – but it seems tricky and to yield no more than default = null, unless perhaps null is a supported argument to Foo(string).
References
¹ Language Specification 5.0 §10.5.2.2 10.5.2.2 Versioning of constants and static readonly fields
² I recall reading this, but have not found it in the Language Specification.
I recently encountered this scenario, and while searching for a solution I stumbled on this page. Based on the example above, I was able to resolve my issue like this:
private static readonly String ConStr
= string.Format("Data Source={0};Initial Catalog={1}; User ID={2}; Password={3};",
Properties.Settings.Default.DataSource,
Properties.Settings.Default.Catalog,
Properties.Settings.Default.UserID,
Properties.Settings.Default.Password);
Just wanted to share.

How do I get default values of optional parameters?

I have a constructor with optional parameters. I would like to have an expression to invoke that constructor without providing the optional arguments (I mean let the object be constructed with default values of the parameters).
I read here An expression tree may not contain a call or invocation that uses optional arguments that this is not possible.
I mean
var ctorInfo = getIt;
var f = Expression.Lambda<Func<T>>(Expression.New(ctorInfo)).Compile();
fails with System.TypeInitializationException.
Alright, I will pass the default values. But how do I get the default values of the parameters?
ctorInfo.GetParameters().Select(??
Motive: Learning purpose, no real world application.
Edit: Edited out expression-tree tag since its not in the context of building expressions, valid in general too.
According to the documentation for ParameterInfo.RawDefaultValue:
ctorInfo.GetParameters().Select( p => p.RawDefaultValue );
Hope it helps
EDIT: Corrected property because:
This property [DefaultValue] is used only in the execution context. In the
reflection-only context, use the RawDefaultValue property instead.

Detect compiler generated default constructor using reflection in C#

I'm targeting .NET 3.5 SP1 and I'm using CommentChecker to validate my XML documentation, everything works OK until I get to a class like this:
/// <summary>
/// documentation
/// </summary>
public sealed class MyClass {
/// <summary>
/// documentation
/// </summary>
public void Method() {
}
}
In the example above, as I understand, the compiler generates a default constructor for my class. The problem with this is that CommentChecker generates warnings telling me that the constructor is missing the comments.
I tried to modify the program to detect this special case and ignore it but I'm stuck, I already tried with IsDefined(typeof(CompilerGeneratedAttribute), true) but that did not work.
So in short, how can I detect the default constructor using reflection?
If you're willing to dig a little into the IL, then you can get most of the way there.
First, assuming you have ConstructorInfo instance which you know to be parameterless, you can get the method body and the bytes for the method body like so (we'll start building an extension method to do this):
public static bool MightBeCSharpCompilerGenerated(
this ConstructorInfo constructor)
{
// Validate parmaeters.
if (constructor == null) throw new ArgumentNullException("constructor");
// If the method is static, throw an exception.
if (constructor.IsStatic)
throw new ArgumentException("The constructor parameter must be an " +
"instance constructor.", "constructor");
// Get the body.
byte[] body = constructor.GetMethodBody().GetILAsByteArray();
You can reject any method bodies don't have seven bytes.
// Feel free to put this in a constant.
if (body.Length != 7) return false;
The reason will be obvious in the code that follows.
In section I.8.9.6.6 of ECMA-335 (Common Language Infrastructure (CLI) Partitions I to VI), it states CLS rule 21:
CLS Rule 21: An object constructor shall call some instance
constructor of its base class before any access occurs to inherited
instance data. (This does not apply to value types, which need not
have constructors.)
This means that before anything else is done, the a base constructor must be called. We can check for this in the IL. The IL for this would look like this (I've put the byte values in parenthesis before the IL command):
// Loads "this" on the stack, as the first argument on an instance
// method is always "this".
(0x02) ldarg.0
// No parameters are loaded, but metadata token will be explained.
(0x28) call <metadata token>
We can now start checking the bytes for this:
// Check the first two bytes, if they are not the loading of
// the first argument and then a call, it's not
// a call to a constructor.
if (body[0] != 0x02 || body[1] != 0x28) return false;
Now comes the metadata token. The call instruction requires a method descriptor to be passed in the form of a metadata token along with the constructor. This is a four-byte value which is exposed through the MetadataToken property on the MemberInfo class (from which ConstructorInfo derives).
We could check to see that the metadata token was valid, but because we've already checked the length of byte array for the method body (at seven bytes), and we know that there's only one byte left to check (first two op codes + four byte metadata token = six bytes), we don't have to check to see that it's to a parameterless constructor; if there were parameters, there would be other op codes to push the parameters on the stack, expanding the byte array.
Finally, if nothing else is done in the constructor (indicating that the compiler generated a constructor that does nothing but call the base), a ret instruction would emitted after the call the metadata token:
(0x2A) ret
Which we can check like so:
return body[6] == 0x2a;
}
It needs to be noted why the method is called MightBeCSharpCompilerGenerated, with an emphasis on Might.
Let's say you have the following classes:
public class Base { }
public class Derived : Base { public Derived() { } }
When compiling without optimizations (typically DEBUG mode), the C# compiler will insert a few nop codes (presumably to assist the debugger) for the Derived class which would cause a call to MightBeCSharpCompilerGenerated to return false.
However, when optimizations are turned on (typically, RELEASE mode), the C# compiler will emit the seven-byte method body without the nop opcodes, so it will look like Derived has a compiler-generated constructor, even though it does not.
This is why the method is named Might instead of Is or Has; it indicates that there might be a method that you need to look at, but can't say for sure. In other words, you'll never get a false negative but you still have to investigate if you get a positive result.
There is no way to detect automatically generated default constructors through metadata. You can test this by creating a class library with two classes, one with an explicit default constructor, and one without. Then run ildasm on the assembly: the metadata of the two constructors is identical.
Rather than try to detect generated constructors, I would simply change the program to allow missing documentation on any default constructor. Most documentation generation programs, like NDoc and SandcastleGUI, have an option to add standard documentation to all default constructors; so it's really not necessary to document them at all. If you have an explicit default constructor in your code, you can put three slashes (///) above the constructor - nothing else - to disable the Visual Studio warning about missing documentation.
The following code will return information on any parameterless constructors in your type:
var info = typeof(MyClass).GetConstructor(new Type[] {});
I do not know of a way of differentiating between a default constructor and an explicitly specified parameterless constructor.
A possible workaround for your CommentChecker issue would be to explicitly create the parameterless constructor where one is required and comment it appropriately.

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