im currently expanding my knowledge a little, and wanted to Create a little game for myself.
The Structure is as Following:
Programm.cs creates an instance of Gamecontroller. This Gamecontroller is the lowest level i want to Access. It will create instaces of the Views, and from classes like config.
I want to implement an debug Console with Command Input. These Commands should always start at the Gamecontroller level, and should be able to interact with kinda everything i could do with C# code.
So i want to access the Objects, Member and methods withing Gamecontroller, or Within any nested object.
Currently i cant get to the Properties of an Child, because _member returns an "Type" which gets parsed to RuntimeProperty instead of the Class
Example on Parsing:
"objPlayer.name" > "GameController.objPlayer.name"
"objConfig.someSetting = 10" > "GameController.objConfig.someSetting=10"
"objConfig.functionCall()" > "GameController.objConfig.functionCall()"
"objConfig.objPlayer.setName("someName")" > "GameController.objConfig.objPlayer.setName("someName")"
"objPlayer.name" > "GameController.objPlayer.name"
this is what i got so far:
private void parseComamnd(string Command)
{
var actions = Command.Split('.');
var start = this.GetType();
var last = actions[actions.Length - 1];
foreach (var action in actions)
{
if (action.Contains("(") && action.Contains(")"))
{
_exec(start, action);
}
else
{
start = _member(start, action);
}
}
}
private Type _member(Type pHandle, string pStrMember)
{
return pHandle.GetProperty(pStrMember).GetType();
}
private void _exec(Type pHandle, string pStrFunction)
{
var Regex = new Regex(#"\(|,|\)");
var FunctionParams = Regex.Split(pStrFunction);
var FunctionName = FunctionParams[0];
FunctionParams[0] = "";
FunctionParams = FunctionParams.Where(val => val != "").ToArray();
pHandle.GetMethod(FunctionName).Invoke(FunctionName, FunctionParams);
}
If I understood right, you want to match some string commands with actions you want to perform. In this case you could use Dictionary as a storage for string-delgate couples to match your string commands to actions you want to perform. As an advantage of this approach, you can change matched couples during program runtime as you wish
class SomeClass
{
delegate void OperationDelegate(string value);
IDictionary<string, OperationDelegate> Operations = new Dictionary<string, OperationDelegate>();
public SomeClass()
{
Operations.Add("objPlayer.name", SetName);
Operations.Add("objConfig.someSetting", SetSetting);
}
public void HandleNewValue(string command, string value)
{
try
{
if (Operations.ContainsKey(command))
Operations[command](value);
}
catch (Exception e)
{
Logger.Error(e);
}
}
private void SetName(string value)
{
// Some logic there
}
private void SetSetting(string value)
{
// Some logic there
}
}
Related
I am trying to write a code analyzer that will check if there are any IDataReaders that are not closed.
I have gone through this question but it does not explain how it can be done, I have also tried to read through the documentation in the github link The English language used here is too complicated and I did not understand how I will be able to find all instances of type IDataReader and verify that the method close() is being called on it before any variable of the said type goes out of scope.
I have tried creating a project of type Analyzer with code fix in visual studio, I tried to register the operation context in the Initialize method of my class (Which is extended from the type DiagnosticAnalyzer as follows:
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class DataReaderAnalyzerAnalyzer : DiagnosticAnalyzer
{
public const string DiagnosticId = "DataReaderAnalyzer";
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(Resources.AnalyzerTitle), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(Resources.AnalyzerMessageFormat), Resources.ResourceManager, typeof(Resources));
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(Resources.AnalyzerDescription), Resources.ResourceManager, typeof(Resources));
private const string Category = "DBConnectionCheck";
private static DiagnosticDescriptor Rule = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, Category, DiagnosticSeverity.Error, isEnabledByDefault: true, description: Description);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get { return ImmutableArray.Create(Rule); } }
public override void Initialize(AnalysisContext context)
{
context.RegisterOperationAction((operationContext) =>
{
((Microsoft.CodeAnalysis.CSharp.Syntax.AssignmentExpressionSyntax)((Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionStatementSyntax)operationContext.Operation.Syntax).Expression).Left
}
, OperationKind.ExpressionStatement);
}
}
I want to find all the references of the occurrence of the variable that holds the type IDataReader, make sure that the close method is being called in this variable before it is lost out of scope.
A sample of my code that I would like to analyze is as follows.
class Program
{
static void Main(string[] args)
{
IDataReader reader = null;
try
{
Database db = DatabaseFactory.CreateDatabase("ApplicationConnection");
reader = GetDataReader(db);
while (reader.Read())
{
//Do somethig with the data here
}
reader.Close();
}
catch (Exception)
{
throw;
}
finally
{
if (reader != null && !reader.IsClosed)
{
reader.Close();
}
}
}
public static IDataReader GetDataReader(Database db)
{
DbCommand dbcmd = db.GetSqlStringCommand("some select statement to get data from oracle data base");
var reader = db.ExecuteReader(dbcmd);
return reader;
}
}
Ultimately, the code shown isn't great, and IMO it would be the wrong solution to write an analyzer to enforce it.
There is a very simple way of doing this style of operation, and it mostly involves forgetting about Close, and using the fact that it is IDisposable - which is the intended API for this kind of scenario. Then it becomes much, much simpler - so much simpler that a: you don't need a special analyzer for it, and b: existing analyzers that work against IDisposable probably do the job for you.
using var reader = GetDataReader(db);
while (reader.Read())
{
//Do somethig with the data here
}
with no try/catch/finally etc; the compiler will add everything you need for this to do the right thing, simply via the using. Note that with older compilers, this needs to be:
using (var reader = GetDataReader(db))
{
while (reader.Read())
{
//Do somethig with the data here
}
}
As a side note: I would strongly suggest not fighting the ADO.NET API - it isn't a useful way of spending your time; tools like Dapper do most common things for you, so you don't need to write this code - and it knows all the corner cases to avoid.
A typical Dapper usage might be:
string region = ...
var users = connection.Query<User>(
"some * from Users where Region = #region",
new { region } // parameters
).AsList();
with the library dealing with all the ADO.NET details internally.
The below code is a non battle hardened approach you can follow.
analysisContext.RegisterCompilationStartAction(compilationContext =>
{
var variables = new HashSet<string>();
var tree = compilationContext.Compilation.SyntaxTrees.First();
//iterate over all childnodes starting from root
foreach (var node in tree.GetRoot().ChildNodes())
{
var flat = Flatten(node).ToList();
//find all variable declarations
var varDecls = flat.OfType<VariableDeclarationSyntax>();
foreach (var decl in varDecls)
{
if (!(decl.Type is IdentifierNameSyntax id)) continue;
if (!id.Identifier.Text.Equals("IDataReader")) continue;
//if you are declaring an IDataReader, go store the var name in set
foreach (var reader in decl.Variables)
{
variables.Add(reader.Identifier.Text);
}
}
//find all method calls i.e. reader.Read() etc
var invokes = flat.OfType<InvocationExpressionSyntax>();
foreach (var invoke in invokes)
{
var memberAccess = invoke.Expression as MemberAccessExpressionSyntax;
var ident = memberAccess.Expression as IdentifierNameSyntax;
if(!variables.Contains(ident.Identifier.Text)) continue;
var name = memberAccess.Name as IdentifierNameSyntax;
//if we find any Close() method on reader, remove from var set
if (name.Identifier.Text.Equals("Close"))
{
variables.Remove(ident.Identifier.Text);
}
}
}
// if we have any variables left in set it means Close() was never called
if (variables.Count != 0)
{
//this is where you can report
//var diagnostic = Diagnostic.Create(Rule, location, value);
//context.ReportDiagnostic(diagnostic);
}
});
public static IEnumerable<SyntaxNode> Flatten(SyntaxNode node)
{
yield return node;
var childNodes = node.ChildNodes();
foreach (var child in childNodes)
foreach (var descendant in Flatten(child))
yield return descendant;
}
I'm building a console application to help expidite some stuff I do regularly. I have a menu with 4 options of procedures, which translate to different methods in my class.
Basicaly it's kind of like this:
What do you want to do?
1 This Thing
2 That Thing
3 Some Stuff
4 Cool Stuff
0 All The Stuff.
Input command string:_
Currently I'm checking for valid input with:
while (command.IndexOfAny("12340".ToCharArray()) == -1)
{
//Display the menu and accept input
}
And then controlling flow with:
if (command.IndexOf("1") > 0 )
{
thisThing();
}
if (command.IndexOf("2") > 0 )
{
thatThing();
}
if (command.IndexOf("3") > 0 )
{
someStuff();
}
if (command.IndexOf("4") > 0 )
{
coolStuff();
}
if (command.IndexOf("0") > 0 )
{
thisThing();
thatThing();
someStuff();
coolStuff();
}
The goal is to provide input and run one or more processes as indicated:
1 : thisThing()
13 : thisThing() and someStuff();
42 : thatThing() and coolStuff();
0 : run all processes I have defined.
Is there a way to do something like this with better practices?
I would create an Dictionary<char, DoSomething>
public delegate void DoSomething();
Dictionary<char, DoSomething> commands = new Dictionary<char, DoThing>();
commands.Add('0', new DoSomething(DoAll));
commands.Add('1', new DoSomething(ThisThing));
commands.Add('2', new DoSomething(ThatThing));
commands.Add('3', new DoSomething(SomeStuff));
commands.Add('4', new DoSomething(CoolStuff));
Then, after input validation
foreach(char c in command.ToCharArray())
{
// Better check if the input is valid
if(commands.ContainsKey(c))
commands[c].Invoke();
}
The Dictionary contains, as keys, the chars allowed and, as values, the delegate to a function with void return and no arguments. Now it is just a matter of looping on the input char by char and invoke the associated method.
Keep present that this approach, with so few choiches, is no better that a simple if/else if/else or switch/case. Also in this way, your user could type 24 or 42 inverting the order of execution of the methods and this could not be allowed in your real context.
I'd create a Dictionary of delegates. Dictionary key would be the input value, and the delegate would execute the code.
The syntax is covered here C# Store functions in a Dictionary.
This way you can step the input string in a loop and do a dictionary lookup; if the value exists execute the delegate, otherwise skip.
Its not specifically better than a If else if endif set, although I'd find it more attractive and extensible.
I have found a very nice way to do it based on regexes in a Ayende Rahien project where he parses the content of the Freedb.org data files
Basically the parser sets up a list of Tuple<Regex, Action<contextual class>> with the contextual class changing depending on the place where the parser is at the time. Parsing then becomes trying to match each element (in this case line) with a regex and executing the corresponding action if it matches.
In your case you could be able to link your commands to multiple inputs, eg
public class Parser
{
readonly List<Tuple<Regex, Action>> actions = new List<Tuple<Regex, Action>>();
public Parser()
{
Add(#"^0$", () => { DoSomething(); });
Add(#"^DoSomething$", () => { DoSomething(); });
Add(#"^1$", () => { DoSomethingElse() });
Add(#"^DoSomethingElse$", () => { DoSomethingElse() });
// etc
}
private void Add(string regex, Action action)
{
var key = new Regex(regex, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
actions.Add(Tuple.Create(key, action));
}
public void Parse(string text)
{
foreach (var action in actions)
{
var collection = action.Item1.Matches(text);
try
{
action.Item2();
}
catch (Exception e)
{
// log?
throw;
}
}
}
}
which lets you run the methods you want with differents inputs.
I'd create an Interface which all commands derive from and have a switch statement determine which action to execute.
Something along the lines of...
public abstract class ISystem
{
public abstract void DoSomething();
}
public class ThisThing : ISystem
{
public override void DoSomething()
{
Console.WriteLine("Do This Thing");
}
}
public class ThatThing : ISystem
{
public override void DoSomething()
{
Console.WriteLine("Do That Thing");
}
}
static void Main(string[] args)
{
var input = "-1";
while(/*input is invalid*/)
{
// get input from user
}
var thisThing = new ThisThing();
var thatThing = new ThatThing();
switch(input)
{
case "1":
{
thisThing.DoSomething();
break;
}
case "2":
{
thatThing.DoSomething();
break;
}
case "0":
{
var commands = new List<ISystem>();
commands.Add(thisThing);
commands.Add(thatThing);
// Execute all commands
commands.ForEach(system => system.DoSomething());
break;
}
}
}
The advantage here is that every time a new command is added then it just needs to implement the DoSomething() method, after that it's just the trivial task of creating an instance of the class var someStuff = new SomeStuff(); and then added to the list of commands in the case "0":
Plus IMO the intention is clearer to read than managing a Dictionary etc.
Currently I'm implementing a Screen indicating wheater a module is not existing or still in development.
The Back Button has the following code:
regionNavigationService.Journal.GoBack();
This is working as expected. But the user is not coming from the Home Screen. So I need to access the View Name from the last Entry in Navigation Journal.
Example: User is coming from Settings Screen => The text should display "Back to Settings Screen"
Assuming the view name you are looking for is when you do new Uri("Main", UriKind.Relative) that you would want the word Main as the view name.
The forward and backward stacks in the RegionNavigationJournal are private. You could use reflection to get access to it.
var journal = regionNavigationService.Journal as RegionNavigationJournal;
if (journal != null)
{
var stack =
(Stack<IRegionNavigationJournalEntry>)
typeof (RegionNavigationJournal).GetField("backStack",
BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(journal);
var name = stack.Peek().Uri.OriginalString;
}
Or a better way is to implement your own IRegionNavigationJournal that is a wrapper around it. This is using Unity to constructor inject the default RegionNavigationJournal if using MEF you might need to put the ImportingConstructorAttribute on it.
public class RegionNavigationJournalWrapper : IRegionNavigationJournal
{
private readonly IRegionNavigationJournal _regionNavigationJournal;
private readonly Stack<Uri> _backStack = new Stack<Uri>();
// Constructor inject prism default RegionNavigationJournal to wrap
public RegionNavigationJournalWrapper(RegionNavigationJournal regionNavigationJournal)
{
_regionNavigationJournal = regionNavigationJournal;
}
public string PreviousViewName
{
get
{
if (_backStack.Count > 0)
{
return _backStack.Peek().OriginalString;
}
return String.Empty;
}
}
public bool CanGoBack
{
get { return _regionNavigationJournal.CanGoBack; }
}
public bool CanGoForward
{
get { return _regionNavigationJournal.CanGoForward; }
}
public void Clear()
{
_backStack.Clear();
_regionNavigationJournal.Clear();
}
public IRegionNavigationJournalEntry CurrentEntry
{
get { return _regionNavigationJournal.CurrentEntry; }
}
public void GoBack()
{
// Save current entry
var currentEntry = CurrentEntry;
// try and go back
_regionNavigationJournal.GoBack();
// if currententry isn't equal to previous entry then we moved back
if (CurrentEntry != currentEntry)
{
_backStack.Pop();
}
}
public void GoForward()
{
// Save current entry
var currentEntry = CurrentEntry;
// try and go forward
_regionNavigationJournal.GoForward();
// if currententry isn't equal to previous entry then we moved forward
if (currentEntry != null && CurrentEntry != currentEntry)
{
_backStack.Push(currentEntry.Uri);
}
}
public INavigateAsync NavigationTarget
{
get { return _regionNavigationJournal.NavigationTarget; }
set { _regionNavigationJournal.NavigationTarget = value; }
}
public void RecordNavigation(IRegionNavigationJournalEntry entry)
{
var currentEntry = CurrentEntry;
_regionNavigationJournal.RecordNavigation(entry);
// if currententry isn't equal to previous entry then we moved forward
if (currentEntry != null && CurrentEntry == entry)
{
_backStack.Push(currentEntry.Uri);
}
}
}
If using unity in your Prism Bootstrapper you will need to replace the default registration of the IRegionNavigationJournal
protected override void ConfigureContainer()
{
this.RegisterTypeIfMissing(typeof(IRegionNavigationJournal), typeof(RegionNavigationJournalWrapper), false);
base.ConfigureContainer();
}
If using MEF you will need to put the ExportAttribute on top of the RegionNavigationJournalWrapper
[Export(typeof(IRegionNavigationJournal))]
You can see http://msdn.microsoft.com/en-us/library/gg430866%28v=pandp.40%29.aspx for more information on replacing their default implementation with your own. Once you have the wrapper you will still need to cast it as RegionNavigationJournalWrapper to get access to the PreviousViewName so still not perfect or create an interface that RegionNavigationJournalWrapper also implements to cast to that to get you access to the PreviousViewName
I'm maintaining a legacy WebForms application and one of the pages just serves GET requests and works with many query string parameters. This work is done in the code-behind and does a lot of this type of check and casting.
protected override void OnLoad(EventArgs e)
{
string error = string.Empty;
string stringParam = Request.Params["stringParam"];
if (!String.IsNullOrEmpty(stringParam))
{
error = "No parameter";
goto LoadError;
}
Guid? someId = null;
try
{
someId = new Guid(Request.Params["guidParam"]);
}
catch (Exception){}
if (!someId.HasValue)
{
error = "No valid id";
goto LoadError;
}
// parameter checks continue on
LoadError:
log.ErrorFormat("Error loading page: {0}", error);
// display error page
}
I'd like to create a testable class that encapsulates this parsing and validation and moves it out of the code-behind. Can anyone recommend some approaches to this and/or examples?
As a first big step, I'd probably create some form of mapper/translator object, like this:
class SpecificPageRequestMapper
{
public SpecificPageRequest Map(NameValueCollection parameters)
{
var request = new SpecificPageRequest();
string stringParam = parameters["stringParam"];
if (String.IsNullOrEmpty(stringParam))
{
throw new SpecificPageRequestMappingException("No parameter");
}
request.StringParam = stringParam;
// more parameters
...
return request;
}
}
class SpecificPageRequest
{
public string StringParam { get; set; }
// more parameters...
}
Then your OnLoad could look like this:
protected override void OnLoad(EventArgs e)
{
try
{
var requestObject = requestMapper.Map(Request.Params);
stringParam = requestObject.StringParam;
// so on, so forth. Unpack them to the class variables first.
// Eventually, just use the request object everywhere, maybe.
}
catch(SpecificPageRequestMappingException ex)
{
log.ErrorFormat("Error loading page: {0}", ex.Message);
// display error page
}
}
I've omitted the code for the specific exception I created, and assumed you instantiate a mapper somewhere in the page behind.
Testing this new object should be trivial; you set the parameter on the collection passed into Map, then assert that the correct parameter on the request object has the value you expect. You can even test the log messages by checking that it throws exceptions in the right cases.
Assuming that you may have many such pages using such parameter parsing, first create a simple static class having extension methods on NamedValueCollection. For example,
static class Parser
{
public static int? ParseInt(this NamedValueCollection params, string name)
{
var textVal = params[name];
int result = 0;
if (string.IsNullOrEmpty(textVal) || !int.TryParse(textVal, out result))
{
return null;
}
return result;
}
public static bool TryParseInt(this NamedValueCollection params, string name, out int result)
{
result = 0;
var textVal = params[name];
if (string.IsNullOrEmpty(textVal))
return false;
return int.TryParse(textVal, out result);
}
// ...
}
Use it as follows
int someId = -1;
if (!Request.Params.TryParseInt("SomeId", out someId))
{
// error
}
Next step would be writing page specific parser class. For example,
public class MyPageParser
{
public int? SomeId { get; private set; }
/// ...
public IEnumerable<string> Parse(NamedValueCollection params)
{
var errors = new List<string>();
int someId = -1;
if (!params.TryParseInt("SomeId", out someId))
{
errors.Add("Some id not present");
this.SomeId = null;
}
this.SomeId = someId;
// ...
}
}
I would like to get property name when I'm in it via reflection. Is it possible?
I have code like this:
public CarType Car
{
get { return (Wheel) this["Wheel"];}
set { this["Wheel"] = value; }
}
And because I need more properties like this I would like to do something like this:
public CarType Car
{
get { return (Wheel) this[GetThisPropertyName()];}
set { this[GetThisPropertyName()] = value; }
}
Since properties are really just methods you can do this and clean up the get_ returned:
class Program
{
static void Main(string[] args)
{
Program p = new Program();
var x = p.Something;
Console.ReadLine();
}
public string Something
{
get
{
return MethodBase.GetCurrentMethod().Name;
}
}
}
If you profile the performance you should find MethodBase.GetCurrentMethod() is miles faster than StackFrame. In .NET 1.1 you will also have issues with StackFrame in release mode (from memory I think I found it was 3x faster).
That said I'm sure the performance issue won't cause too much of a problem- though an interesting discussion on StackFrame slowness can be found here.
I guess another option if you were concerned about performance would be to create a Visual Studio Intellisense Code Snippet that creates the property for you and also creates a string that corresponds to the property name.
Slightly confusing example you presented, unless I just don't get it.
From C# 6.0 you can use the nameof operator.
public CarType MyProperty
{
get { return (CarType)this[nameof(MyProperty)]};
set { this[nameof(MyProperty)] = value]};
}
If you have a method that handles your getter/setter anyway, you can use the C# 4.5 CallerMemberName attribute, in this case you don't even need to repeat the name.
public CarType MyProperty
{
get { return Get<CarType>(); }
set { Set(value); }
}
public T Get<T>([CallerMemberName]string name = null)
{
return (T)this[name];
}
public void Set<T>(T value, [CallerMemberName]string name = null)
{
this[name] = value;
}
I'd like to know more about the context in which you need it since it seems to me that you should already know what property you are working with in the property accessor. If you must, though, you could probably use MethodBase.GetCurrentMethod().Name and remove anything after get_/set_.
Update:
Based on your changes, I would say that you should use inheritance rather than reflection. I don't know what data is in your dictionary, but it seems to me that you really want to have different Car classes, say Sedan, Roadster, Buggy, StationWagon, not keep the type in a local variable. Then you would have implementations of methods that do the proper thing for that type of Car. Instead of finding out what kind of car you have, then doing something, you then simply call the appropriate method and the Car object does the right thing based on what type it is.
public interface ICar
{
void Drive( decimal velocity, Orientation orientation );
void Shift( int gear );
...
}
public abstract class Car : ICar
{
public virtual void Drive( decimal velocity, Orientation orientation )
{
...some default implementation...
}
public abstract void Shift( int gear );
...
}
public class AutomaticTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
public class ManualTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
Use MethodBase.GetCurrentMethod() instead!
Reflection is used to do work with types that can't be done at compile time. Getting the name of the property accessor you're in can be decided at compile time so you probably shouldn't use reflection for it.
You get use the accessor method's name from the call stack using System.Diagnostics.StackTrace though.
string GetPropertyName()
{
StackTrace callStackTrace = new StackTrace();
StackFrame propertyFrame = callStackTrace.GetFrame(1); // 1: below GetPropertyName frame
string properyAccessorName = propertyFrame.GetMethod().Name;
return properyAccessorName.Replace("get_","").Replace("set_","");
}
FWIW I implemented a system like this:
[CrmAttribute("firstname")]
public string FirstName
{
get { return GetPropValue<string>(MethodBase.GetCurrentMethod().Name); }
set { SetPropValue(MethodBase.GetCurrentMethod().Name, value); }
}
// this is in a base class, skipped that bit for clairty
public T GetPropValue<T>(string propName)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
return GetAttributeValue<T>(attributeName);
}
public void SetPropValue(string propName, object value)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
SetAttributeValue(attributeName, value);
}
private static Dictionary<string, string> PropToAttributeMap = new Dictionary<string, string>();
private string GetCrmAttributeName(string propertyName)
{
// keyName for our propertyName to (static) CrmAttributeName cache
string keyName = this.GetType().Name + propertyName;
// have we already done this mapping?
if (!PropToAttributeMap.ContainsKey(keyName))
{
Type t = this.GetType();
PropertyInfo info = t.GetProperty(propertyName);
if (info == null)
{
throw new Exception("Cannot find a propety called " + propertyName);
}
object[] attrs = info.GetCustomAttributes(false);
foreach (object o in attrs)
{
CrmAttributeAttribute attr = o as CrmAttributeAttribute ;
if (attr != null)
{
// found it. Save the mapping for next time.
PropToAttributeMap[keyName] = attr.AttributeName;
return attr.AttributeName;
}
}
throw new Exception("Missing MemberOf attribute for " + info.Name + "." + propertyName + ". Could not auto-access value");
}
// return the existing mapping
string result = PropToAttributeMap[keyName];
return result;
}
There's also a custom attribute class called CrmAttributeAttribute.
I'd strongly recommend against using GetStackFrame() as part of your solution, my original version of the solution was originally the much neater:
return GetPropValue<string>();
But it was 600x slower than the version above.
Solution # 1
var a = nameof(SampleMethod); //a == SampleMethod
var b = nameof(SampleVariable); //b == SampleVariable
var c = nameof(SampleProperty); //c == SampleProperty
Solution # 2
MethodBase.GetCurrentMethod().Name; // Name of method in which you call the code
MethodBase.GetCurrentMethod().Name.Replace("set_", "").Replace("get_", ""); // current Property
Solution # 3
from StackTrace:
public static class Props
{
public static string CurrPropName =>
(new StackTrace()).GetFrame(1).GetMethod().Name.Replace("set_", "").Replace("get_", "");
public static string CurrMethodName =>
(new StackTrace()).GetFrame(1).GetMethod().Name;
}
you just need to call Props.CurrPropName or Props.CurrMethodName
Solution # 4
Solution for .NET 4.5+:
public static class Props
{
public static string GetCallerName([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
{
return propertyName;
}
}
usage: Props.GetCallerName();
Yes, it is!
string test = "test string";
Type type = test.GetType();
PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < propInfos.Length; i++)
{
PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i);
string propName = pi.Name;
}
Try using System.Diagnostics.StackTrace to reflect on the call stack. The property should be somewhere in the call stack (probably at the top if you're calling it directly from the property's code).