Delegate and method GetFunctionPointer - c#

I am trying to figure out why one of these delegates is working differently under the hood. I have basically these kind of delegates:
private delegate void _SetSomething(bool value);
private delegate Something _Find(string value);
private delegate T _AddSomething<T>();
For each of these I have to know the memory address where they are pointing out, so I used GetFunctionPointer and I got three addresses, nothing special right now except for the fact I have to patch these addresses in memory, so I checked them in disassembly view and I saw for the first two methods the expected behaviours but not for the last:
var obj = new SomethingObj();
obj.SetSomething(true); // E8 XX XX XX XX calling exactly the first address got from the delegate
firstDel.DynamicInvoke(true); // starts calling from the fp value
var ret1 = obj.Find("something"); // E8 XX XX XX XX calling exactly the second address from the delegate
var ret2 = secondDel.DynamicInvoke("something"); // starts calling from the fp value
var ret3 = obj.AddSomething<SomeStuff>(); // E8 XX XX XX XX !!! Here the address does not match with the function pointer got from delegate
var ret4 = thirdDel.DynamicInvoke(null); // starts calling from the fp value...
I am running out of the options, I don't completly understand what is happening with the last delegate except for the fact that it is a little bit more complex of the others.
I don't really understand why is not the same address called by the instance method like the others two, anyone could help me out?
using System;
using System.Linq;
namespace Test
{
internal class Program
{
private static void Main(string[] args)
{
var obj = new SomethingObj();
var firstDel = (_SetSomething) Delegate.CreateDelegate(typeof (_SetSomething), obj, "SetSomething");
var targetFind = typeof (SomethingObj).GetMethod("Find");
var secondDel = (_Find) Delegate.CreateDelegate(typeof (_Find), obj, targetFind, true);
var targetAdd = typeof (SomethingObj).GetMethods()
.First(m => m.Name == "AddSomething" && m.GetParameters().Length == 0)
.MakeGenericMethod(typeof (SomeStuff));
var thirdDel =
(_AddSomething<SomeStuff>) Delegate.CreateDelegate(typeof (_AddSomething<SomeStuff>), obj, targetAdd, true);
var firstAddress = firstDel.Method.MethodHandle.GetFunctionPointer();
var secondAddress = secondDel.Method.MethodHandle.GetFunctionPointer();
var thirdAddress = thirdDel.Method.MethodHandle.GetFunctionPointer();
obj.SetSomething(true); // E8 XX XX XX XX calling exactly the first address got from the delegate
firstDel.DynamicInvoke(true); // starts calling from the fp value
var ret1 = obj.Find("something"); // E8 XX XX XX XX calling exactly the second address from the delegate
var ret2 = secondDel.DynamicInvoke("something"); // starts calling from the fp value
var ret3 = obj.AddSomething<SomeStuff>(); // E8 XX XX XX XX !!! Here the address does not match with the function pointer got from delegate
var ret4 = thirdDel.DynamicInvoke(null); // starts calling from the fp value...
}
public class SomethingObj
{
public void SetSomething(bool value)
{
}
public SomeStuff AddSomething(Type type)
{
return new SomeStuff();
}
public T AddSomething<T>() where T : SomeStuff
{
return new SomeStuff() as T;
}
public SomeStuff AddSomething(string className)
{
return new SomeStuff();
}
public SomeStuff Find(string value)
{
return new SomeStuff();
}
}
public class SomeStuff
{
}
public class SomeStuffTest : SomeStuff
{
}
private delegate void _SetSomething(bool value);
private delegate SomeStuff _Find(string value);
private delegate T _AddSomething<T>();
}
}

Related

How can I change field value with Mono Cecil?

I have a C# program and it has a class:
public class Test
{
internal const string a = "some value";
private DateTime b = new DateTime();
}
How can I use Mono Cecil to change their initial value so that it looks like this:
public class Test
{
internal const string a = "test";
private DateTime b = DateTime.MaxValue;
}
Right now I only have the following skeleton code and I don't know how to modify the fields.
void Main()
{
var input = #"C:\my_projects\a.exe";
var asm = AssemblyDefinition.ReadAssembly(input);
foreach (ModuleDefinition module in asm.Modules)
{
foreach (TypeDefinition type in module.GetTypes())
{
foreach (var field in type.Fields)
{
if (field.Name == "a")
{
}
else if (field.Name == "b")
{
}
}
}
}
asm.Write(#"c:\my_projects\b.exe");
}
Disclaimer
Very brittle code ahead
For the constant it is a matter of setting fld.Constant property.
For instance/static fields the C# compiler will emit the initialization code in the constructor, so you'll need to find the instruction that is loading the value that will be stored in the field and replace it.
using System.IO;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace x
{
class Program
{
public const string ConstValue = "old";
public int instanceField = 1;
static void Main(string[] args)
{
var o = new Program();
if (o.instanceField == 1)
{
using var a = AssemblyDefinition.ReadAssembly(typeof(Program).Assembly.Location);
var t = a.MainModule.Types.Single(ct => ct.Name == "Program");
var constant = t.Fields.First(f => f.Name == "ConstValue");
constant.Constant = "new value";
var ctor = t.Methods.Single(m => m.IsConstructor);
System.Console.WriteLine(ctor);
var il = ctor.Body.GetILProcessor();
var inst = il.Body.Instructions.First();
while (inst != null)
{
System.Console.WriteLine($"Checking {inst}");
if (inst.OpCode == OpCodes.Stfld && ((FieldReference) inst.Operand).Name == "instanceField")
{
// notice that this is very fragile. For this specific
// case I'd say it is safe but depending on how you
// initialize the field the instruction that loads
// the value to be assigned to the field may be located
// several instructions prior to the actual assignment
// but you can keep track of the stack state and figure
// out which instruction is pushing the value that
// will end up being poped into the field.
il.Replace(inst.Previous, il.Create(OpCodes.Ldc_I4, 42));
System.Console.WriteLine("Found");
break;
}
inst = inst.Next;
}
var p = typeof(Program).Assembly.Location;
var newBinaryPath = Path.Combine(Path.GetDirectoryName(p), Path.GetFileNameWithoutExtension(p) + "2" +Path.GetExtension(p));
a.Write(newBinaryPath);
System.Console.WriteLine($"New binary writen to {newBinaryPath}");
}
System.Console.WriteLine(o.instanceField);
// Notice that no matter what you do, this will always print the
// old value; that happens because the C# compiler will emit the
// constant at the call site (instead of referencing the field
// at runtime)
System.Console.WriteLine(ConstValue);
}
}
}

C# - pass on variable amount of parameters to other method within a method

I know the title is a little bit tricky to understand, but the following example should clarify what I mean:
Imagine you have a method with 2 overloads:
void Method(int i)
{
Console.WriteLine("Method(int) called");
}
void Method(int i, string s)
{
Console.WriteLine("Method(int, string) called");
}
Then you have another method that takes a variable amount of parameters:
void MethodOverload(params dynamic[] parameters)
{
Method(parameters); // Call one of the overloading methods depending on the parameter amount and their type
}
The method above accepts any amount of parameters with any type. I want to call one of the overloading methods depending on the amount of passed parameters and their type.
For example:
void Run()
{
TestFuncOverload(5); // Output: "testFunc(int) called"
TestFuncOverload(5, "some text"); // Output: "testFunc(int, string) called"
TestFuncOverload(5, 5); //Error
}
How does one achieve this in C#?
You could do it with reflection but I don't recommend it. Reflection is slow and to do this you need to use it a lot. You should try to solve it with a different approach, but in case you really need to do it this way, this should do the trick:
public void MethodOverload(params dynamic[] parameters)
{
//Check if the array is null
if (parameters == null)
throw new ArgumentNullException(nameof(parameters));
//Create a list of the types in the dynamic[]
var inputParameterTypes = new Type[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
inputParameterTypes[i] = parameters[i].GetType();
}
const string NameOfMethod = nameof(Method); //This should be the name of your method which will be called
//Get every method from this class which has the name you are looking for
var methods = this.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Where(x => x.Name == NameOfMethod);
foreach (var method in methods)
{
//Get the parameters of the method
var methodParameters = method.GetParameters();
if (methodParameters.Length != inputParameterTypes.Length)
continue;
//Check if the types match with the input parameters
var match = true;
for (int i = 0; i < methodParameters.Length; i++)
{
//Check if the type matches
if (methodParameters[i].ParameterType == inputParameterTypes[i])
continue;
//Doesn't match
match = false;
}
if (!match)
continue;
//Call the method and return
method.Invoke(this, parameters);
return;
}
//If this is reached no valid methods were found
throw new Exception("No valid methods found!");
}
(This code assumes that all methods are in the same class)
After doing some measurements with this code:
var a = new Foo();
var parameters = new dynamic[][]
{
new dynamic[] { 1, "Test" },
new dynamic[] { 2 }
};
var sw = Stopwatch.StartNew();
for (int i = 0; i < Num; i++)
{
a.MethodOverload(parameters[i % 2]);
}
sw.Stop();
Console.WriteLine($"{Num} iterations took {sw.Elapsed.TotalMilliseconds} milliseconds. Average time: {sw.Elapsed.TotalMilliseconds / Num} milliseconds");
(Removed the Console.WriteLine from the called functions)
here are the results:
10000000 iterations took 5283.9398 milliseconds. Average time: 0.00052839398 milliseconds
100000000 iterations took 51244.9142 milliseconds. Average time: 0.000512449142 milliseconds
I could do that with below code. It costs tons of reflection, you can consider another approach to avoid performance problems.
public class Test
{
private void Method(int i)
{
Console.WriteLine("Method(int) called");
}
private void Method(int i, string s)
{
Console.WriteLine("Method(int, string) called");
}
public void Method(params object[] parameters)
{
var m = typeof(Test).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public)
.Where(x => x.Name == "Method" &&
!x.GetParameters()
.Any(p => p.IsDefined(typeof(ParamArrayAttribute), false)))
.Where(x => x.GetParameters().Count() == parameters.Count())
.Where(x => x.GetParameters()
.Select(y => Type.GetType("System." + y.ParameterType.Name))
.Zip(parameters.Select(z => z.GetType()), Equals)
.All(q => q))
.FirstOrDefault();
if(m == null) throw new Exception ("method not found");
//null result because of void method.
var result = m.Invoke(this, parameters);
}
}
static void Main(string[] args)
{
Test t = new Test();
//"Method(int) called"
t.Method(0);
//"Method(int, string) called"
t.Method(0, "");
//throws ex
t.Method("", "");
}
You'll need to use Reflection and call the method by Invoke.

Return array of doubles from a registered delegate method of other class

Supossing I have button, when is pressed then It registers methods from other previously created class, and I am interested on result from OtherClassLeftReleasedCb from other method, so:
private void MainClassBtn_Click(object sender, RoutedEventArgs e)
{
vtkInteractorObserver istyle = goPreviewer.ImageViewer.GetRenderWindow().GetInteractor().GetInteractorStyle();
istyle.LeftButtonReleaseEvt += new vtkObject.vtkObjectEventHandler(OtherClass.OtherClassLeftReleasedCb);
}
the method of other class works fine, however I want to return array like:
public void OtherClassLeftReleasedCb(vtkObject sender, vtkObjectEventArgs e)
{
//do stuff
myresult = new double[4];
myresult [0] = stuffcomputedbefore[0];
myresult [1] = stuffcomputedbefore[0] - stuffcomputedbefore[0];
myresult [2] = stuffcomputedbefore2[1];
myresult [3] = stuffcomputedbefore2[1] - stuffcomputedbefore[1];
}
If I change return type to double[] to OtherClassLeftReleasedCb, then I would get error because when doing
istyle.LeftButtonReleaseEvt += new vtkObject.vtkObjectEventHandler(OtherClass.OtherClassLeftReleasedCb);
I am not telling that it should get array od doubles.
I do not know how to get myresult from extern method, Is this even possible?
Rather than having OtherClassLeftReleasedCb conform to the signature of the event that you have, write it using the signature that you want it to be:
public double[] OtherClassLeftReleasedCb()
{
//do stuff
myresult = new double[4];
myresult [0] = stuffcomputedbefore[0];
myresult [1] = stuffcomputedbefore[0] - stuffcomputedbefore[0];
myresult [2] = stuffcomputedbefore2[1];
myresult [3] = stuffcomputedbefore2[1] - stuffcomputedbefore[1];
return myresult ;
}
Then have your other class create another method (possibly an anonymous method, if you want) that calls this other method and then possibly does something with the result:
private void MainClassBtn_Click(object sender, RoutedEventArgs e)
{
vtkInteractorObserver istyle = goPreviewer.ImageViewer.GetRenderWindow()
.GetInteractor().GetInteractorStyle();
istyle.LeftButtonReleaseEvt += (s,args) =>
DoSomethingWithArray(OtherClass.OtherClassLeftReleasedCb());
}

Get types used inside a C# method body

Is there a way to get all types used inside C# method?
For example,
public int foo(string str)
{
Bar bar = new Bar();
string x = "test";
TEST t = bar.GetTEST();
}
would return: Bar, string and TEST.
All I can get now is the method body text using EnvDTE.CodeFunction. Maybe there is a better way to achieve it than trying to parse this code.
I'm going to take this opportunity to post up a proof of concept I did because somebody told me it couldn't be done - with a bit of tweaking here and there, it'd be relatively trivial to extend this to extract out all referenced Types in a method - apologies for the size of it and the lack of a preface, but it's somewhat commented:
void Main()
{
Func<int,int> addOne = i => i + 1;
Console.WriteLine(DumpMethod(addOne));
Func<int,string> stuff = i =>
{
var m = 10312;
var j = i + m;
var k = j * j + i;
var foo = "Bar";
var asStr = k.ToString();
return foo + asStr;
};
Console.WriteLine(DumpMethod(stuff));
Console.WriteLine(DumpMethod((Func<string>)Foo.GetFooName));
Console.WriteLine(DumpMethod((Action)Console.Beep));
}
public class Foo
{
public const string FooName = "Foo";
public static string GetFooName() { return typeof(Foo).Name + ":" + FooName; }
}
public static string DumpMethod(Delegate method)
{
// For aggregating our response
StringBuilder sb = new StringBuilder();
// First we need to extract out the raw IL
var mb = method.Method.GetMethodBody();
var il = mb.GetILAsByteArray();
// We'll also need a full set of the IL opcodes so we
// can remap them over our method body
var opCodes = typeof(System.Reflection.Emit.OpCodes)
.GetFields()
.Select(fi => (System.Reflection.Emit.OpCode)fi.GetValue(null));
//opCodes.Dump();
// For each byte in our method body, try to match it to an opcode
var mappedIL = il.Select(op =>
opCodes.FirstOrDefault(opCode => opCode.Value == op));
// OpCode/Operand parsing:
// Some opcodes have no operands, some use ints, etc.
// let's try to cover all cases
var ilWalker = mappedIL.GetEnumerator();
while(ilWalker.MoveNext())
{
var mappedOp = ilWalker.Current;
if(mappedOp.OperandType != OperandType.InlineNone)
{
// For operand inference:
// MOST operands are 32 bit,
// so we'll start there
var byteCount = 4;
long operand = 0;
string token = string.Empty;
// For metadata token resolution
var module = method.Method.Module;
Func<int, string> tokenResolver = tkn => string.Empty;
switch(mappedOp.OperandType)
{
// These are all 32bit metadata tokens
case OperandType.InlineMethod:
tokenResolver = tkn =>
{
var resMethod = module.SafeResolveMethod((int)tkn);
return string.Format("({0}())", resMethod == null ? "unknown" : resMethod.Name);
};
break;
case OperandType.InlineField:
tokenResolver = tkn =>
{
var field = module.SafeResolveField((int)tkn);
return string.Format("({0})", field == null ? "unknown" : field.Name);
};
break;
case OperandType.InlineSig:
tokenResolver = tkn =>
{
var sigBytes = module.SafeResolveSignature((int)tkn);
var catSig = string
.Join(",", sigBytes);
return string.Format("(SIG:{0})", catSig == null ? "unknown" : catSig);
};
break;
case OperandType.InlineString:
tokenResolver = tkn =>
{
var str = module.SafeResolveString((int)tkn);
return string.Format("('{0}')", str == null ? "unknown" : str);
};
break;
case OperandType.InlineType:
tokenResolver = tkn =>
{
var type = module.SafeResolveType((int)tkn);
return string.Format("(typeof({0}))", type == null ? "unknown" : type.Name);
};
break;
// These are plain old 32bit operands
case OperandType.InlineI:
case OperandType.InlineBrTarget:
case OperandType.InlineSwitch:
case OperandType.ShortInlineR:
break;
// These are 64bit operands
case OperandType.InlineI8:
case OperandType.InlineR:
byteCount = 8;
break;
// These are all 8bit values
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
case OperandType.ShortInlineVar:
byteCount = 1;
break;
}
// Based on byte count, pull out the full operand
for(int i=0; i < byteCount; i++)
{
ilWalker.MoveNext();
operand |= ((long)ilWalker.Current.Value) << (8 * i);
}
var resolved = tokenResolver((int)operand);
resolved = string.IsNullOrEmpty(resolved) ? operand.ToString() : resolved;
sb.AppendFormat("{0} {1}",
mappedOp.Name,
resolved)
.AppendLine();
}
else
{
sb.AppendLine(mappedOp.Name);
}
}
return sb.ToString();
}
public static class Ext
{
public static FieldInfo SafeResolveField(this Module m, int token)
{
FieldInfo fi;
m.TryResolveField(token, out fi);
return fi;
}
public static bool TryResolveField(this Module m, int token, out FieldInfo fi)
{
var ok = false;
try { fi = m.ResolveField(token); ok = true; }
catch { fi = null; }
return ok;
}
public static MethodBase SafeResolveMethod(this Module m, int token)
{
MethodBase fi;
m.TryResolveMethod(token, out fi);
return fi;
}
public static bool TryResolveMethod(this Module m, int token, out MethodBase fi)
{
var ok = false;
try { fi = m.ResolveMethod(token); ok = true; }
catch { fi = null; }
return ok;
}
public static string SafeResolveString(this Module m, int token)
{
string fi;
m.TryResolveString(token, out fi);
return fi;
}
public static bool TryResolveString(this Module m, int token, out string fi)
{
var ok = false;
try { fi = m.ResolveString(token); ok = true; }
catch { fi = null; }
return ok;
}
public static byte[] SafeResolveSignature(this Module m, int token)
{
byte[] fi;
m.TryResolveSignature(token, out fi);
return fi;
}
public static bool TryResolveSignature(this Module m, int token, out byte[] fi)
{
var ok = false;
try { fi = m.ResolveSignature(token); ok = true; }
catch { fi = null; }
return ok;
}
public static Type SafeResolveType(this Module m, int token)
{
Type fi;
m.TryResolveType(token, out fi);
return fi;
}
public static bool TryResolveType(this Module m, int token, out Type fi)
{
var ok = false;
try { fi = m.ResolveType(token); ok = true; }
catch { fi = null; }
return ok;
}
}
If you can access the IL for this method, you might be able to do something suitable. Perhaps look at the open source project ILSpy and see whether you can leverage any of their work.
As others have mentioned, if you had the DLL you could use something similar to what ILSpy does in its Analyze feature (iterating over all the IL instructions in the assembly to find references to a specific type).
Otherwise, there is no way to do it without parsing the text into a C# Abstract Syntax Tree, AND employing a Resolver - something that can understand the semantics of the code well enough to know if "Bar" in your example is indeed a name of a type that is accessible from that method (in its "using" scope), or perhaps the name of a method, member field, etc... SharpDevelop contains a C# parser (called "NRefactory") and also contains such a Resolver, you can look into pursuing that option by looking at this thread, but beware that it is a fair amount of work to set it up to work right.
I just posted an extensive example of how to use Mono.Cecil to do static code analysis like this.
I also show a CallTreeSearch enumerator class that can statically analyze call trees, looking for certain interesting things and generating results using a custom supplied selector function, so you can plug it with your 'payload' logic, e.g.
static IEnumerable<TypeUsage> SearchMessages(TypeDefinition uiType, bool onlyConstructions)
{
return uiType.SearchCallTree(IsBusinessCall,
(instruction, stack) => DetectTypeUsage(instruction, stack, onlyConstructions));
}
internal class TypeUsage : IEquatable<TypeUsage>
{
public TypeReference Type;
public Stack<MethodReference> Stack;
#region equality
// ... omitted for brevity ...
#endregion
}
private static TypeUsage DetectTypeUsage(
Instruction instruction, IEnumerable<MethodReference> stack, bool onlyConstructions)
{
TypeDefinition resolve = null;
{
TypeReference tr = null;
var methodReference = instruction.Operand as MethodReference;
if (methodReference != null)
tr = methodReference.DeclaringType;
tr = tr ?? instruction.Operand as TypeReference;
if ((tr == null) || !IsInterestingType(tr))
return null;
resolve = tr.GetOriginalType().TryResolve();
}
if (resolve == null)
throw new ApplicationException("Required assembly not loaded.");
if (resolve.IsSerializable)
if (!onlyConstructions || IsConstructorCall(instruction))
return new TypeUsage {Stack = new Stack<MethodReference>(stack.Reverse()), Type = resolve};
return null;
}
This leaves out a few details
implementation of IsBusinessCall, IsConstructorCall and TryResolve as these are trivial and serve as illustrative only
Hope that helps
The closest thing to that that I can think of are expression trees. Take a look at the documentation from Microsoft.
They are very limited however and only work on simple expressions and not full methods with statement bodies.
Edit: Since the intention of the poster was to find class couplings and used types, I would suggest using a commercial tool like NDepend to do the code analysis as an easy solution.
This definitely cannot be done from reflection (GetMethod(), Expression Trees, etc.). As you mentioned, using EnvDTE's CodeModel is an option since you get line-by-line C# there, but using it outside Visual Studio (that is, processing an already existing function, not in your editor window) is nigh-impossible, IMHO.
But I can recommend Mono.Cecil, which can process CIL code line-by-line (inside a method), and you can use it on any method from any assembly you have reference to. Then, you can check every line if it is a variable declaration (like string x = "test", or a methodCall, and you can get the types involved in those lines.
With reflection you can get the method. This returns a MethodInfo object, and with this object you cannot get the types which are used in the method. So I think the answer is that you cannot get this native in C#.

print name of the variable in c#

i have a statement
int A = 10,B=6,C=5;
and i want to write a print function such that i pass the int variable to it and
it prints me the variable name and the value.
eg if i call print(A)
it must return "A: 10", and print (B) then it must return "B:6"
in short i want to know how can i access the name of the variable and print it to string in c#. DO i have to use reflection?
After reading the answers
Hi all, thanks for the suggestions provided. I shall try them out, however i wanted to know if it is at all possible in .NET 2.0? Nothing similar to
#define prt(x) std::cout << #x " = '" << x << "'" << std::endl;
macro which is there in C/C++?
The only sensible way to do this would be to use the Expression API; but that changes the code yet further...
static void Main() {
int A = 10, B = 6, C = 5;
Print(() => A);
}
static void Print<T>(Expression<Func<T>> expression) {
Console.WriteLine("{0}={1}",
((MemberExpression)expression.Body).Member.Name,
expression.Compile()());
}
Note: if this is for debugging purposes, be sure to add [Conditional("DEBUG")] to the method, as using a variable in this way changes the nature of the code in subtle ways.
You can use lambda expressions:
static void Main( string[] args ) {
int A = 50, B = 30, C = 17;
Print( () => A );
Print( () => B );
Print( () => C );
}
static void Print<T>( System.Linq.Expressions.Expression<Func<T>> input ) {
System.Linq.Expressions.LambdaExpression lambda = (System.Linq.Expressions.LambdaExpression)input;
System.Linq.Expressions.MemberExpression member = (System.Linq.Expressions.MemberExpression)lambda.Body;
var result = input.Compile()();
Console.WriteLine( "{0}: {1}", member.Member.Name, result );
}
This is not possible without some 'help' from the call site; even reflection does not know about names of local variables.
This is not possible to do with reflection (see Brian and Joel). In general this is not possible simply because you cannot guarantee a named value is being passed to your print function. For instance, I could just as easily do the following
print(42);
print(A + 42);
Neither of these expressions actually has a name. What would you expect to print here?
Another solution (from a closed post):
Inspired by Jon Skeet's post about Null Reference exception handling and suddenly being reminded about projection there is a way to kinda do that.
Here is complete working codez:
public static class ObjectExtensions {
public static string GetVariableName<T>(this T obj) {
System.Reflection.PropertyInfo[] objGetTypeGetProperties = obj.GetType().GetProperties();
if(objGetTypeGetProperties.Length == 1)
return objGetTypeGetProperties[0].Name;
else
throw new ArgumentException("object must contain one property");
}
}
class Program {
static void Main(string[] args) {
string strName = "sdsd";
Console.WriteLine(new {strName}.GetVariableName());
int intName = 2343;
Console.WriteLine(new { intName }.GetVariableName());
}
}
If you need to support more types than int, use the Expression API but avoid generics and handle the different expression gracefully:
private static string ToDebugOutput(params Expression<Func<object>>[] variables)
{
var sb = new StringBuilder();
foreach (var input in variables)
{
string name;
if (input.Body is UnaryExpression unary && unary.Operand is MemberExpression operand)
{
name = operand.Member.Name;
}
else if (input.Body is MemberExpression member)
{
name = member.Member.Name;
}
else
{
throw new NotSupportedException($"typeof lambda: {input.Body.GetType()}");
}
var result = input.Compile()();
sb.Append($"{name}={result}, ");
}
return sb.ToString();
}
Usage:
string s = "123";
double d = 1.23;
int i2 = 123;
var out2 = ToDebugOutput(() => s, () => d, () => i2);
// out2 = "s=123, d=1.23, i2=123, "

Categories