Recursively get variable name - c#

I try to get recursively the name of a variable, for example for the variable test.child, if I follow this topic, I only get child and I have no idea how to get all the parents.
Here is my test code:
public static class MemberInfoGetting
{
public static string GetMemberName<T>(Expression<Func<T>> memberExpression)
{
MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
return expressionBody.Member.Name;
}
}
public class Test
{
public string child = "childValue";
}
static void Main(string[] args)
{
//string testVariable = "value";
Test test = new Test();
test.child = "newValue";
string nameOfTestVariable = MemberInfoGetting.GetMemberName(() => test.child);
Console.WriteLine(nameOfTestVariable + " | " + test.child);
Console.Read();
}

I throw this in as the first intent: (not 100% done, still thinking about it, at least it handles your sample)
public static class MemberInfoGetting {
public static string GetMemberName<T>(Expression<Func<T>> memberExpression) {
MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
var str = expressionBody.ToString();
var lst = str.Split('.').Skip(2).ToList(); //This needs LINQ, otherwise do it manually
StringBuilder retVal = new StringBuilder();
for (int i = 0; i < lst.Count; i++) {
retVal.Append(lst[i]);
if(i != lst.Count -1) {
retVal.Append(".");
}
}
return retVal.ToString();
}
}

Then maybe it is useful to have something like:
public class Test
{
public string value = "Value";
public Test child;
public Test(Test childObject)
{
this.child = childObject;
}
}
You can use this object for recursion then. As now you have nested objects.
Something like this:
Test child = new Test(null);
Test parent = new Test(child);
So, if you create a method which takes as parameter the parent object in this case, you can get the parent and the child values as well. In this case, the exit condition of your recursion method being the Test object that has a null child.

Related

Get expression arguments?

Ok, here is the problem:
int a = 111;
int b = 222;
Expression<Func<int>> expr = ()=> someClass.SomeWork(a) + b + 1;
As you see, there is 3 different arguments: someClass, a, b. They are all from another scope of execution, but one isn't. How I can get them? I mean, in general, I want only variables of outter scope.
For example, I want to use it like this:
var result = InvokeAndLog(expr);//this will invoke expression and print out everything I need from these arguments.
Ok, folks, I found answer myself. And here it is:
internal class Program
{
public static int Method1()
{
return new Random(0).Next(10000);
}
public class MyClass
{
private int var = 11111;
public int GetSome(int val)
{
return var * val;
}
}
private static void Main()
{
var clas = new MyClass();
int a = 111;
int b = 222;
Expression<Func<int>> expr = () => a * 2 - clas.GetSome(b) + b + 1 - Method1();
var result = InvokeAndLog(expr);
}
private static T InvokeAndLog<T>(Expression<Func<T>> expr)
{
var visitor = new ArgumentsVisitor();
visitor.Visit(expr);
Console.WriteLine("Inputs: {0}", string.Join(", ", visitor.Arguments));
return expr.Compile()();
}
}
The main class here is ExpressionVisitor descendant. I just overrided its member visitor and aggregated all members into single set:
public class ArgumentsVisitor : ExpressionVisitor
{
private readonly HashSet<MemberInfo> _all = new HashSet<MemberInfo>();
public IEnumerable<MemberInfo> Arguments
{
get { return _all; }
}
protected override Expression VisitMember(MemberExpression node)
{
_all.Add(node.Member);
return base.VisitMember(node);
}
}
Then I applyed visitor to expression and printed out all variables! Thanks, microsoft =)

How to set nested property value using FastMember

I get an exception when I try to set a nested member Property using FastMember. For example when having these classes
public class A
{
public B First { get; set; }
}
public class B
{
public string Second { get; set; }
}
and I want to set First.Second of an instance to "hello".
var b = new B{ Second = "some value here" };
var a = new A{ First = b };
var accessor = ObjectAccessor.Create(a);
accessor["First.Second"] = value; // this does not work and gives ArgumentOutOfRangeException
I can't split it up into ["First"]["Second"] because I don't know the depth at this point. Is there a magical access for nested properties or do I have to split the hierarchy myself?
I solved the problem recursively using an Extension Method this way:
public static class FastMemberExtensions
{
public static void AssignValueToProperty(this ObjectAccessor accessor, string propertyName, object value)
{
var index = propertyName.IndexOf('.');
if (index == -1)
{
accessor[propertyName] = value;
}
else
{
accessor = ObjectAccessor.Create(accessor[propertyName.Substring(0, index)]);
AssignValueToProperty(accessor, propertyName.Substring(index + 1), value);
}
}
}
... and this is started as follows:
ObjectAccessor.Create(a).AssignValueToProperty("First.Second", "hello")
You need to traverse the object graph using multiple ObjectAccessor instances.
public static void UseFastMember()
{
var b = new B { Second = "some value here" };
var a = new A { First = b };
var value = "hello";
var a_accessor = ObjectAccessor.Create(a);
var first = a_accessor["First"];
var b_accessor = ObjectAccessor.Create(first);
b_accessor["Second"] = value;
}
Hats off to #Beachwalker for the inspiration. But should you be using TypeAccessor as opposed to ObjectAccessor this is an extension method I've had much success with:
public static class TypeAccessorExtensions
{
public static void AssignValue<T>(this TypeAccessor accessor, T t, MemberSet members, string fieldName, object fieldValue)
{
var index = fieldName.IndexOf('.');
if (index == -1)
{
if (members.Any(m => string.Equals(m.Name, fieldName, StringComparison.OrdinalIgnoreCase)))
accessor[t, fieldName] = fieldValue;
}
else
{
string fieldNameNested = fieldName.Substring(0, index);
var member = members.FirstOrDefault(m => string.Equals(m.Name, fieldNameNested, StringComparison.OrdinalIgnoreCase));
if (member != null)
{
var nestedAccesor = TypeAccessor.Create(member.Type);
var tNested = accessor[t, fieldNameNested];
if (tNested == null)
{
tNested = Activator.CreateInstance(member.Type);
accessor[t, fieldNameNested] = tNested;
}
nestedAccesor.AssignValue(tNested, nestedAccesor.GetMembers(), fieldName.Substring(index + 1), fieldValue);
}
}
}
}

C# - Class with List<> of other Classes

I have a class, that has several elements of normal types, like int, String, etc.
It also has several elements that are various lists of other classes, that could be empty or have 1 to many items.
I have a function that I call with a generic type of the parent class, and I want to analyze data that could be in the sub elements, without knowing the types.
I am getting the parent members with the following code:
var getProperty = System.Runtime.CompilerServices.
CallSite<Func<System.Runtime.CompilerServices.CallSite,
object, object>>
.Create(Microsoft.CSharp.RuntimeBinder.
Binder.GetMember(0, property.Name, thisObject.GetType(), new[]
{
Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null)
}));
var thisValue = getProperty.Target(getProperty, thisObject);
I get the value into the var thisValue. At this point if I determine the underlying type of thisValue is a type of list, how can I grab the type of the list contents?
Here is the actual function....I can't seem to get it formatted nicely.
public static bool ObjectIsLike<T>(this T thisObject, T compareObject, params object[] argumentsToExclude)
{
for (int counter = 0; counter < argumentsToExclude.Length - 1; counter++)
{
argumentsToExclude[counter] = argumentsToExclude[counter].ToString().ToUpper();
}
bool objectIsLike = true;
foreach (var property in thisObject.GetType().GetProperties())
{
string fieldName = property.Name;
if (!argumentsToExclude.Contains(fieldName.ToUpper()))
{
try
{
var getProperty = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, property.Name, thisObject.GetType(), new[] { Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null) }));
var thisValue = getProperty.Target(getProperty, thisObject);
getProperty = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, property.Name, compareObject.GetType(), new[] { Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0, null) }));
var compareValue = getProperty.Target(getProperty, compareObject);
if (!(compareValue == null && thisValue == null))
{
if (compareValue == null || thisValue == null)
objectIsLike = false;
else
if (compareValue.GetType().FullName.Contains("List"))
{
//Ignore Lists
}
else
if (!compareValue.Equals(thisValue))
{
objectIsLike = false;
}
}
}
catch
{
objectIsLike = false;
}
}
}
return objectIsLike;
}
would GetType() work for you?
class Program
{
static void Main(string[] args)
{
MyClass1 c1 = new MyClass1();
foreach (var s in c1.pp)
{
Console.WriteLine(s.GetType());
}
Console.Read();
}
}
public class MyClass1
{
public MyClass2 p;
public List<object> pp;
public MyClass1()
{
p = new MyClass2();
pp = new List<object>();
pp.Add(new MyClass2());
pp.Add(new MyClass3());
pp.Add(new MyClass4());
}
}
public class MyClass2
{
public List<object> ppp;
public MyClass2()
{
ppp = new List<object>();
ppp.Add(new MyClass3());
ppp.Add(new MyClass4());
}
}
public class MyClass3
{
public int v;
}
public class MyClass4
{
public int v;
}

Get type name without any generics info

If I write:
var type = typeof(List<string>);
Console.WriteLine(type.Name);
It will write:
List`1
I want it to write just:
List
How can I do that?
Is there a smarter way to do it without having to use Substring or similar string manipulation functions?
No, it makes perfect sense for it to include the generic arity in the name - because it's part of what makes the name unique (along with assembly and namespace, of course).
Put it this way: System.Nullable and System.Nullable<T> are very different types. It's not expected that you'd want to confuse the two... so if you want to lose information, you're going to have to work to do it. It's not very hard, of course, and can be put in a helper method:
public static string GetNameWithoutGenericArity(this Type t)
{
string name = t.Name;
int index = name.IndexOf('`');
return index == -1 ? name : name.Substring(0, index);
}
Then:
var type = typeof(List<string>);
Console.WriteLine(type.GetNameWithoutGenericArity());
No, it doesn't, because the "generic-type-string" is part of the name of type.
If someone is interested, I created some extensionmethods for this problem that create a more "readable" string
it produces something like
List[string]
outer.inner[other.whatever]
IEnumerable[T0]
Dictionary[string:int]
Test here
public static class TypeEx
{
public static string GetTypeName(this Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (!type.IsGenericType)
return type.GetNestedTypeName();
StringBuilder stringBuilder = new StringBuilder();
_buildClassNameRecursiv(type, stringBuilder);
return stringBuilder.ToString();
}
private static void _buildClassNameRecursiv(Type type, StringBuilder classNameBuilder, int genericParameterIndex = 0)
{
if (type.IsGenericParameter)
classNameBuilder.AppendFormat("T{0}", genericParameterIndex + 1);
else if (type.IsGenericType)
{
classNameBuilder.Append(GetNestedTypeName(type) + "[");
int subIndex = 0;
foreach (Type genericTypeArgument in type.GetGenericArguments())
{
if (subIndex > 0)
classNameBuilder.Append(":");
_buildClassNameRecursiv(genericTypeArgument, classNameBuilder, subIndex++);
}
classNameBuilder.Append("]");
}
else
classNameBuilder.Append(type.GetNestedTypeName());
}
public static string GetNestedTypeName(this Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (!type.IsNested)
return type.Name;
StringBuilder nestedName = new StringBuilder();
while(type != null)
{
if(nestedName.Length>0)
nestedName.Insert(0,'.');
nestedName.Insert(0, _getTypeName(type));
type = type.DeclaringType;
}
return nestedName.ToString();
}
private static string _getTypeName(Type type)
{
return type.IsGenericType ? type.Name.Split('`')[0]: type.Name;
}
}
static void Main(string[] args)
{
Console.WriteLine(WhatIsMyType<IEnumerable<string>>());
Console.WriteLine(WhatIsMyType<List<int>>());
Console.WriteLine(WhatIsMyType<IList<int>>());
Console.WriteLine(WhatIsMyType<List<ContentBlob>>());
Console.WriteLine(WhatIsMyType<int[]>());
Console.WriteLine(WhatIsMyType<ContentBlob>());
Console.WriteLine(WhatIsMyType<Dictionary<string, Dictionary<int, int>>>());
}
public static string WhatIsMyType<T>()
{
return typeof(T).NameWithGenerics();
}
public static string NameWithGenerics(this Type type)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
if (type.IsArray)
return $"{type.GetElementType()?.Name}[]";
if (!type.IsGenericType)
return type.Name;
var name = type.GetGenericTypeDefinition().Name;
var index = name.IndexOf('`');
var newName = index == -1 ? name : name.Substring(0, index);
var list = type.GetGenericArguments().Select(NameWithGenerics).ToList();
return $"{newName}<{string.Join(",", list)}>";
}
Example output:
IEnumerable<String>
List<Int32>
IList<Int32>
List<ContentBlob>
Int32[]
ContentBlob
Dictionary<String,Dictionary<Int32,Int32>>
Here's the code from this answer inside a static class and namespace for easier copy-and-pasting.
Also, there's another extension method to get the type its namespace.
using System;
namespace TODO
{
public static class TypeExtensions
{
/// <summary>
/// From: https://stackoverflow.com/a/6386234/569302
/// </summary>
public static string GetNameWithoutGenericArity(this Type t)
{
string name = t.Name;
int index = name.IndexOf('`');
return index == -1 ? name : name.Substring(0, index);
}
public static string GetFullNameWithoutGenericArity(this Type t)
{
var result = $"{t.Namespace}.{t.GetNameWithoutGenericArity()}";
return result;
}
}
}
The easiest way I can think of as of C#6(I think) you can do the following:
public static void Main(string[] args)
{
Console.WriteLine(nameof(List<int>));
Console.WriteLine(nameof(Dictionary<int, int>));
}
This will print:
List
Dictionary

How to convert chained static class names and a property value to a string?

Context:
Suppose one has the following class structure:
public static class SomeStaticClass
{
public static class SomeInnerStaticClass
{
public static readonly string SomeProperty = "someStringValue";
}
}
Question:
Is there an easy way to convert the reference SomeStaticClass.SomeInnerStaticClass.SomeProperty to string value of "SomeStaticClass.SomeInnerStaticClass.someStringValue"?
the first thing I posted was wrong because they were static types I wrote a little code and this works.
public static class A
{
public static class B
{
public static string c
{
get
{
return "hi";
}
}
}
}
class Program
{
static void Main( string[] args )
{
Console.WriteLine(typeof(A.B).FullName.Replace("+",".") + "." + A.B.c ) ;
}
}
Don't you just want:
public static class SClass
{
public static class SInner
{
public static string Property =
(typeof(SInner)).DeclaringType.Name+ "."
+ typeof(SInner).Name + "."
+ "value";
}
}
Which would output SClass.SInner.Property.value
If you wanted to automated it, you could put it in a while loop and exit once the parent type propertyIsNested is false.
You could use an expression:
namespace ConsoleApplication2
{
using System;
using System.Linq.Expressions;
class Program
{
static void Main(string[] args)
{
string fullName = GetExpression(() => SomeClass.SomeProperty);
Console.WriteLine(fullName);
}
public static string GetExpression<TProperty>(Expression<Func<TProperty>> expr)
{
string name = expr.Body.ToString();
string value = expr.Compile().Invoke().ToString();
name = name.Substring(0, name.LastIndexOf(".") + 1) + value;
return name;
}
}
public static class SomeClass
{
public static string SomeProperty = "Hello";
}
}
Here's one more elaborate solution. The method accepts a lambda expression denoting a property or a field. It the computes the value of the property or field and prepends it with names of all encapsulating classes.
I guess you want to have a type-safe method of producing some kind of structured / hierarchical identifiers encoded as a hierarchy of classes and properties or fields. I've been using this approach for a few years and it helps prevent many hard-to-catch bugs caused by simple typos.
Code:
public string GetStructuredName(Expression<Func<object>> nameObject)
{
if (nameObject == null) throw new ArgumentNullException("nameObject");
// find the expression denoting a property or a field
MemberExpression member = null;
switch (nameObject.Body.NodeType)
{
case ExpressionType.MemberAccess:
member = (MemberExpression)nameObject.Body;
break;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
member = ((UnaryExpression)nameObject.Body).Operand as MemberExpression;
break;
}
if (member == null) throw new ArgumentNullException("nameObject");
StringBuilder sb = new StringBuilder();
// use the value of the member as the final component of the resulting name
sb.Append(nameObject.Compile().DynamicInvoke());
// use short names of embedded type names as components of the resulting name
Type type = member.Member.DeclaringType;
while (type != null && type != typeof(Object))
{
sb.Insert(0, ".");
sb.Insert(0, type.Name);
type = type.DeclaringType;
}
return sb.ToString();
}
Example:
public class OuterContainer
{
public class InnerContainer
{
public static string Property
{
get { return "value"; }
}
public static int Field = 10;
}
}
GetStructuredName(() => OuterContainer.InnerContainer.Property)
GetStructuredName(() => OuterContainer.InnerContainer.Field)
The output will be:
"OuterContainer.InnerContainer.value"
"OuterContainer.InnerContainer.10"
I don't know about the nature of your input format, but you can do this with System.Linq.Expressions:
Expression<Func<string>> expr = () =>
SomeStaticClass.SomeInnerStaticClass.SomeProperty;
var myResult = String.Concat(expr.Body, ".", expr.Compile().Invoke());

Categories

Resources