I am trying to use CallerMemberName attribute in .NET 4.0 via BCL portability pack. It is always returning an empty string instead of the member name. What am I doing wrong?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
MessageBox.Show(new class2().CallMe);
}
}
public class class2
{
public string CallMe
{
get
{
return HelpMe();
}
}
private string HelpMe([CallerMemberName] string param = "")
{
return param;
}
}
Targeting 4.0 works just fine if you add:
namespace System.Runtime.CompilerServices {
sealed class CallerMemberNameAttribute : Attribute { }
}
I found the solution, though it's not useful to me. You need to install KB2468871 on top of .NET Framework 4 to be able to use caller info attributes. Unfortunately, I can't ask each developer to remember to install it when they setup development environment.
As I know, CallerMemberName is supported from .Net 4.5
You should not use it in .Net 4.0
Someone implemented this in .Net 4.0 using StackTrace. for example:
http://www.journeyintocode.com/2013/04/callermembername-net-40.html
BUT, I do NOT recommend you to use the StackTrace since there could be a performance hit.
Using StackTrace to get the caller name is very very slow. And this works in Debug, in release you cannot be sure whether StackTrace is "correct" or not.
So, my suggestion is: Just use CallerMemberName in .Net 4.5 or later version.
In the early version of .Net, there isn't any foolproof or fast way of doing this.
Related
I'm trying to access Microsoft.SignalR library from Python for .Net in Visual Studio, and some of the implementation of a Hub (IHubProxy) is in an extension: HubProxyExtensions
Python for .Net does not seem to cover extensions in the readme, and I can't find any reference (my google fu is not working in this case.)
I'm able to load the extensions class directly, but calling the method fails:
ext = SignalR.Client.HubProxyExtensions
ext.On(self._proxy, method, handle)
The extension class loads and reports as a meta class and has methods from the immediate window
ext
<CLR Metatype>
dir(ext)
['Equals', 'Finalize', 'GetHashCode', 'GetType', 'GetValue', MemberwiseClone', 'Observe', 'On', 'Overloads', 'ReferenceEquals', 'ToString', __call__', '__class__', '__cmp__', ...]
Calling ext.On() crashes the process.
Does Python for .Net support extensions at all? (Or is it just a problem specific to this particular implementation)
Update: Doing a simple test on extensions, it looks like Python for .Net does handle extensions properly, so there is something wrong with my call to Signalr specifically... more testing to come.
So I'm going to answer my own question since it turned out to be multiple issues; and I didn't see others addressing this directly.
Action templates:
The problem in my case is there is no way to bind Action templates in Python for .Net. So there is no way to call the correct On methods in a hub.
Someone else found the same issue recently
Extensions:
Python for .Net can call extension methods; Simply call the static extension method through the extension class like any other static class methods.
C#
namespace ExtensionTest
{
public class MyClass
{
public string MyMethod(string something)
{
System.Console.Out.WriteLine(string.Format("Hi! This is something! {0}", something));
return something + " something else";
}
}
}
namespace ExtensionTest
{
public static class MyExtension
{
public static string MyExtensionMethod(this MyClass myclass, string something)
{
System.Console.Out.WriteLine(string.Format("This is the extension {0}", something));
string somethingelse = myclass.MyMethod(something);
return somethingelse + " more of something";
}
}
}
Python:
import clr
clr.AddReference('ExtensionTest')
import ExtensionTest
obj = ExtensionTest.MyClass()
s = obj.MyMethod('Hi')
print s
s = ExtensionTest.MyExtension.MyExtensionMethod(obj, 'Hello!')
Output:
Hi! This is something! Hi
Hi something else
This is the extension Hello!
Hi! This is something! Hello!
Hello! something else more of something
I'm not sure why this isn't mentioned on the readme for python for .net.
I guess it's obvious :)
I have an old line of c# code that looks basically like this:
foo.set_Parent(parent);
It has compiled fine for years. Now in VS2015 I get the error:
CS0571 'Foo.Parent.set': cannot explicitly call operator or accessor
So I can rewrite the line as:
foo.Parent=parent;
This builds fine in VS2015, but in VS2013 it gives the error:
'Foo.Parent' is not supported by the language; try directly calling
accessor methods 'Foo.get_Parent()' or Foo.set_Parent(Foo)'
So the simple fix is to simply ifdef these two lines based upon which version of the compiler is running. But how do you detect which version of the compiler is executing?
And for the record, no, I can't just dictate that everyone on the team simultaneously upgrades to VS2015.
Additional info -
For everyone smelling a rat, I'll go ahead and drag out the ugly truth, although I don't think it will change much of anything. The class Foo is from an ancient Borland assembly that is all bound up in Delphi (and yes, we're migrating away but not there yet). So the actual code, that compiles up to VS2013, looks like this:
using Borland.Vcl;
using RepGen;
using SnapReportsForm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace MigrantCOM {
[ComVisible(true)]
[Guid("48245BA3-736B-4F98-BDC5-AD86F77E39F4")]
[ProgId("MigrantCOM.Exports")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class MigrantCLRExports { // : MarshalByRefObject
public string Test(string s) { return s+s; }
}
[ComVisible(true)]
[Guid("1154D364-B588-4C31-88B9-141072303117")]
[ProgId("MigrantCOM.SnapRepCOM")]
[ClassInterface(ClassInterfaceType.AutoDual)]
public class SnapRepCOM {
TRepGen repGen;
TStringList snapRefs=new TStringList();
TForm parent=new TForm(null);
TMemo designerMemo;
List<TReference> references=new List<TReference>();
TRunAsSnapContext runAsSnapContext=new TRunAsSnapContext();
public SnapRepCOM() {
designerMemo=new TMemo(parent); designerMemo.set_Parent(parent);
...
}
So the class being instantiated is Borland.Vcl.TMemo which is part of the old Delphi assembly.
I'm leaving this as an answer, linking an image will fit better here than in a comment.
So if you want to use VS 2015 but still use the same good ol' version of the C# language that worked for years, you can configure your project to target a specific version:
This adds <LangVersion>5</LangVersion> in the csproj.
I'm trying to reproduce the C# compiler error CS0840 with the exact code that's given in the website:
class Test36
{
public int myProp { get; } // CS0840
// to create a read-only property
// try the following line instead
public int myProp2 { get; private set; }
}
public Form1()
{
InitializeComponent();
Test36 test = new Test36();
}
I'm running it on .NET 4.0 using Visual Studio Community 2015. Surprisingly, I cannot reproduce it. Compiler doesn't throw any error:
Why the compiler isn't throwing any error?
You're using Visual Studio 2015, which implements C# 6. The fact that you're targeting .NET 4 is irrelevant - most of the C# 6 language features don't depend on framework features at all. The C# 6 code you're using can easily be compiled without reference to any modern CLR or framework features - it could have worked with .NET 1.0 if the language designers had decided to :)
You'll need to set you language level to C# 5 to see an error here. Do that in the project properties / Build / Advanced dialog:
You'll then get this error:
error CS8026: Feature 'readonly automatically implemented properties' is not available in C# 5. Please use language version 6 or greater.
Admittedly that's not the error you actually wanted to see - I think you'll need to use an earlier version of the compiler to get that exact error.
I guess it is because you are on Visual Studio 2015 with C# 6 which allows you to specify properties that are only set from the constructor (aka read-only properties).
See the following example:
class Test
{
public Test() // <-- this one does compile since it is the constructor
{
MyProp = 1;
}
public void SomeMethod() // <-- this one doesn't compile
{
MyProp = 1;
}
public int MyProp { get; } // <-- no CS0840 any more!
}
Lets suppose if I have created a C# project which uses C# 4.0 features - optional parameter. What will happen if I select '.Net Framework 2.0' as a target framework? Will the compiler be intelligent enough to generate IL compatible with 2.0 on its own or will the Exe give runtime error when deployed on a machine that has only .Net framework 2.0?
In the specific case of optional parameters, compatibility will work as default values to use are stored in the caller's assembly and not in the called assembly so compatibility with other assemblies is ensured. If it compiles, it will run.
Optional parameters are just a syntaxic sugar. The following code compiles and run for a target framework 2.0 :
internal class Program
{
public static class DummyClass
{
public static string Bar(int b = 10, int a = 12)
{
return a.ToString();
}
}
private static void Main(string[] args)
{
Console.WriteLine("{0}", DummyClass.Bar(a: 8));
Console.ReadKey();
}
}
Read a full explanation by Mr Botelho
How can I get the current CLR Runtime version in a running .NET program ?
Check out the System.Environment.Version property.
https://learn.microsoft.com/en-us/dotnet/api/system.environment.version
Since .NET 4.5 you could just use System.Environment.Version (it would only return 4.0.{something}, allowing you to verify that you're "at least" on 4.0 but not telling you which actual version is available unless you can map a full list of build numbers in).
In .NET Core, and starting in .NET 4.7.1 of Framework, you can check System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription
It returns a string with either: ".NET Core", ".NET Framework", or ".NET Native" before the version number -- so you have a little parsing to do if you just want the number.
Try Environment.Version to get that info. Also you may need to call ToString().
That works for me:
public static String GetRunningFrameworkVersion()
{
String netVer = Environment.Version;
Assembly assObj = typeof( Object ).GetTypeInfo().Assembly;
if ( assObj != null )
{
AssemblyFileVersionAttribute attr;
attr = (AssemblyFileVersionAttribute)assObj.GetCustomAttribute( typeof(AssemblyFileVersionAttribute) );
if ( attr != null )
{
netVer = attr.Version;
}
}
return netVer;
}
I compiled my .NET program for .NET 4.5 and it returns for running under .NET 4.8:
"4.8.4150.0"
If you just want to find out the version and don't need it to be parsed or of type Version, just do this:
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
If your app is running via .Net Framework 4.7.2, it returns something like .NET Framework 4.7.3875.0.
If your app is running via .Net 6, it returns something like .NET 6.0.0-rtm.21522.10.