Link to home
Start Free TrialLog in
Avatar of CipherIS
CipherISFlag for United States of America

asked on

C# Get Values from object sender

I am trying to obtain the values from "sender"

User generated image
I attempted to use linq

var x = from temp in sender select temp

Open in new window


but I receive error "Could not find an implementation of the query pattern"

How can I obtain the values in sender?
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Cast "sender" to the correct type...for example:
xyz tmp = (xyz)sender; // where "xyz" is the correct TYPE that sender is (maybe "CameraMessageMonitor"?)
// now do something with "tmp"
Console.WriteLine(tmp.SomeValue.ToString());

Open in new window

Avatar of Russ Suter
Russ Suter

Or you can use safe casting
(sender as Aimetis.Symphony.SDK.NotificationMonitors.CameraMessageMonitor).value

Open in new window

where "value" is the name of the property you're trying to access.

Normally you should do NULL checking after casting like this but in the case where you're casting a sender object you're pretty much guaranteed that the sender is an object and it is of the type you expect. If it isn't someone up the line made a pretty major programming mistake.

You can also significantly shorten the above line by including a using statement to import the namespace. It'll probably be something like this:
using Aimetis.Symphony.SDK.NotificationMonitors;

Open in new window

Then your cast is simply
(sender as CameraMessageMonitor).value

Open in new window

Avatar of CipherIS

ASKER

No error with the casting but the nothing showing  up with intellisense and seem not to be getting any thing.
If you cast like I did above you should get Intellisense. Make sure you use the parentheses.
(sender as Aimetis.Symphony.SDK.NotificationMonitors.CameraMessageMonitor).value

Receive error - CameraMessageMonitor does not contain a definition 'value' and no extension method 'value' accepting first argument of type CameraMessageMonitor could be found.
As I said above, replace "value" with whatever property you want to access. You should get intellisense after you type the last dot "." following the close parenthesis.
Found the value.  Receiving the below error.
Object2.jpg
@Russ Suter

That approach isn't any safer than a direct cast.
var s = (CameraMessageMonitor)sender;

Open in new window


Above code worked.  I'm looking at my watch window and it is returning the below values.  How do I get the values of m_source and also AlarmDataTable and the sub values in there?

Thanks
Object3.jpg
@käµfm³d 👽

Safe cast will return a null value if the cast is invalid. You'll get an exception the other way. Which means it is safer. Exceptions are something to be avoided whenever possible.
Calling .Vaue at the end of the cast as you have written it will most certainly result in a NullReferenceException if the cast fails, hence my comment. If you were to instead do the check for null, as you mentioned in comment, then it would be safer.
This is a technique I use frequently when working inside event handlers. The only two ways that cast could result in an exception are if I cast to the wrong type or the person who wrote the underlying code wrote the event handler wrong. Either way, an exception means bad code. Checking for null when casting the sender argument inside an event handler is unnecessary and wasteful code.
Ok, below code returned the values from the sender object.

var s = (CameraMessageMonitor)sender;

Open in new window


I included an image above "object3" which shows what is stored.

I am trying to get the values in "s".

I tried

var x = (from temp in s select new {}).ToList();

Open in new window


But the error I receive is "Could not find an implementation of the query pattern for source type 'CameraMessageMonitor'.  'Select' not found."

When I add "s" to my watch it provides all the values.
You cannot LINQ against a control**...that doesn't make sense. You LINQ over a collection (i.e. something that implements IEnumerable).


** Unless, of course, some control happens to implement IEnumerable, which is technically possible.
Ok, so how do I get the values?
You want the same "values" that you see in the Watch (i.e. the object/control's properties)?
I'm trying to get to those values.  When I type s.  intellisense gives me below.
object4.jpg
You would need Reflection, then.

e.g.

foreach (System.Reflection.PropertyInfo property in sender.GetType().GetProperties(System.Reflection.BindingFlags.Instance))
{
    string name = property.Name;
    object value = property.GetValue(sender);

    Console.WriteLine("{0} - {1}", name, value.ToString());
}

Open in new window


This is a crude example. You'll probably have to tweak it.
It's not going inside for loop.
The foreach loop in the above wraps the Reflection logic. Maybe I'm misunderstanding what you're trying to do, but based on what I read above you want the value of each property in the object--dynamically--and if so, then you use Reflection. My foreach loop just iterates over the object's properties.
Yes, that is what I want but it is not going inside the loop.
Ah, my mistake. I think it needs another BindingFlag:

foreach (System.Reflection.PropertyInfo property in sender.GetType().GetProperties(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public))

Open in new window

Still not dropping inside for loop.
I tried this and it is still not going inside the for loop.
 foreach (PropertyInfo property in sender.GetType().GetProperties(BindingFlags.CreateInstance |
                                                                             BindingFlags.DeclaredOnly | 
                                                                             BindingFlags.Default |
                                                                             BindingFlags.ExactBinding |
                                                                             BindingFlags.FlattenHierarchy |
                                                                             BindingFlags.GetField | 
                                                                             BindingFlags.GetProperty |
                                                                             BindingFlags.IgnoreCase |
                                                                             BindingFlags.IgnoreReturn |
                                                                             BindingFlags.Instance |
                                                                             BindingFlags.InvokeMethod |
                                                                             BindingFlags.NonPublic |
                                                                             BindingFlags.OptionalParamBinding |
                                                                             BindingFlags.Public |
                                                                             BindingFlags.PutDispProperty |
                                                                             BindingFlags.PutRefDispProperty |
                                                                             BindingFlags.SetField |
                                                                             BindingFlags.Static |
                                                                             BindingFlags.SuppressChangeType
                                                                             ))
            {
                string name = property.Name;
                object value = property.GetValue(sender);

                Console.WriteLine("{0} - {1}", name, value.ToString());
            }

Open in new window

Unsure. It's working fine for me:

User generated image
Note: I did change the logic a small bit to avoid issues with null values.
ReflectedType: '((System.RuntimeType)(s.GetType())).ReflectedType' threw an exception of type 'System.NotSupportedException'
I put the code for the button and it works for the button but not for the CameraMessageMonitor.  Any other way to get the values?
What property are you wanting to get?  The binding flags by default provide instance and public properties.  If you want the private and/or protected properties you will have to add BindingFlags.NonPublic; e.g. -
using System;
using System.Linq;
using System.Reflection;

namespace EE_Q28924773
{
	class Program
	{
		static void Main(string[] args)
		{
			SomeClass _someClass = new SomeClass();

			var _noFlags = (from prop in _someClass.GetType().GetProperties() select new { Name = prop.Name, Value = prop.GetValue(_someClass, null) });
			var _public = (from prop in _someClass.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public) select new { Name = prop.Name, Value = prop.GetValue(_someClass, null) });
			var _nonPublic = (from prop in _someClass.GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic) select new { Name = prop.Name, Value = prop.GetValue(_someClass, null) });

			Console.WriteLine("NoFlag Properties");
			foreach (var item in _noFlags)
				Console.WriteLine(item);

			Console.WriteLine();
			Console.WriteLine("Public Properties");
			foreach (var item in _public)
				Console.WriteLine(item);

			Console.WriteLine();
			Console.WriteLine("NonPublic Properties");
			foreach (var item in _nonPublic)
				Console.WriteLine(item);

			Console.ReadLine();
		}
	}

	class SomeClass
	{
		string _privateStringField = "Private Field";
		protected internal string _protectedInternalStringField = "Protected Internal Field";
		internal string _internalStringField = "Internal Field";
		protected string _protectedStringField = "Protected Field";
		public string _publicStringField = "Public Field";

		string PrivateStringProperty 
		{
			get { return _privateStringField; }
			set { _privateStringField = value; } 
		}

		protected internal string ProtectedInternalStringProperty
		{
			get { return _protectedInternalStringField; }
			set { _protectedInternalStringField = value; }
		}

		internal string InternalStringProperty
		{
			get { return _internalStringField; }
			set { _internalStringField = value; }
		}

		protected string ProtectedStringProperty
		{
			get { return _protectedStringField; }
			set { _protectedStringField = value; }
		}

		public string PublicStringProperty
		{
			get { return _publicStringField; }
			set { _publicStringField = value; }
		}
	}
}

Open in new window

Which produces the following output -User generated imageYou can combine binding flags as well since it is a flag based enumeration; e.g. -
using System;
using System.Linq;
using System.Reflection;

namespace EE_Q28924773
{
	class Program
	{
		static void Main(string[] args)
		{
			SomeClass _someClass = new SomeClass();

			var _allProperties = (from prop in _someClass.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) select new { Name = prop.Name, Value = prop.GetValue(_someClass, null) });

			Console.WriteLine("All Properties");
			foreach (var item in _allProperties)
				Console.WriteLine(item);

			Console.ReadLine();
		}
	}

	class SomeClass
	{
		string _privateStringField = "Private Field";
		protected internal string _protectedInternalStringField = "Protected Internal Field";
		internal string _internalStringField = "Internal Field";
		protected string _protectedStringField = "Protected Field";
		public string _publicStringField = "Public Field";

		string PrivateStringProperty 
		{
			get { return _privateStringField; }
			set { _privateStringField = value; } 
		}

		protected internal string ProtectedInternalStringProperty
		{
			get { return _protectedInternalStringField; }
			set { _protectedInternalStringField = value; }
		}

		internal string InternalStringProperty
		{
			get { return _internalStringField; }
			set { _internalStringField = value; }
		}

		protected string ProtectedStringProperty
		{
			get { return _protectedStringField; }
			set { _protectedStringField = value; }
		}

		public string PublicStringProperty
		{
			get { return _publicStringField; }
			set { _publicStringField = value; }
		}
	}
}

Open in new window

Which produces the following output -User generated imageIf you want fields (because not all fields have properties) then use the GetFields methods with the appropriate binding flags; e.g. -
using System;
using System.Linq;
using System.Reflection;

namespace EE_Q28924773
{
	class Program
	{
		static void Main(string[] args)
		{
			SomeClass _someClass = new SomeClass();

			var _allProperties = (from prop in _someClass.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) select new { Name = prop.Name, Value = prop.GetValue(_someClass, null) });
			var _allFields = (from field in _someClass.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) select new { Name = field.Name, Value = field.GetValue(_someClass) });

			Console.WriteLine("All Properties");
			foreach (var item in _allProperties)
				Console.WriteLine(item);

			Console.WriteLine();
			Console.WriteLine("All Fields");
			foreach (var item in _allFields)
				Console.WriteLine(item);

			Console.ReadLine();
		}
	}

	class SomeClass
	{
		string _privateStringField = "Private Field";
		protected internal string _protectedInternalStringField = "Protected Internal Field";
		internal string _internalStringField = "Internal Field";
		protected string _protectedStringField = "Protected Field";
		public string _publicStringField = "Public Field";

		string PrivateStringProperty { get; set; }
		protected internal string ProtectedInternalStringProperty { get; set; }
		internal string InternalStringProperty { get; set; }
		protected string ProtectedStringProperty { get; set; }
		public string PublicStringProperty { get; set; }
	}
}

Open in new window

Which produces the following output -User generated image-saige-
Also, heed kaufmeds advice on null checking your values (I did not above).

-saige-
Yes, and like I said, the code works for the button.  I tried it but it is not working for
var s = (CameraMessageMonitor)sender;

foreach (PropertyInfo property in s.GetType().GetProperties(BindingFlags.Instance |
                                                                        BindingFlags.Public 
                                                                        ))
{
    string name = property.Name;
    object value = (property.GetValue(sender) ?? null).ToString();

    Console.WriteLine("{0} - {1}", name, value.ToString());
}

Open in new window


The code is NOT going inside the "for loop".

I am trying to get the values in the the attached image
Object3.jpg
In your image.  m_source is a field, not a property.  In order to retrieve this, you need to use the GetField or GetFields method.  Also, m_source is a protected field, which means that you need to include BindingFlags.NonPublic in your list of BindingFlags parameters.

From there, you can then get the properties (the wrench indicates properties) of m_source by retrieving it's type and using GetProperties.

-saige-
I tried below

            foreach (PropertyInfo property in s.GetType().GetProperties(BindingFlags.CreateInstance |
                                                                                         BindingFlags.DeclaredOnly |
                                                                                         BindingFlags.Default |
                                                                                         BindingFlags.ExactBinding |
                                                                                         BindingFlags.FlattenHierarchy |
                                                                                         BindingFlags.GetField |
                                                                                         BindingFlags.GetProperty |
                                                                                         BindingFlags.IgnoreCase |
                                                                                         BindingFlags.IgnoreReturn |
                                                                                         BindingFlags.Instance |
                                                                                         BindingFlags.InvokeMethod |
                                                                                         BindingFlags.NonPublic |
                                                                                         BindingFlags.OptionalParamBinding |
                                                                                         BindingFlags.Public |
                                                                                         BindingFlags.PutDispProperty |
                                                                                         BindingFlags.PutRefDispProperty |
                                                                                         BindingFlags.SetField |
                                                                                         BindingFlags.Static |
                                                                                         BindingFlags.SuppressChangeType
                                                                                         ))

I added one at a time to see if it would drop inside the for loop and it still did not drop in the for loop.
ASKER CERTIFIED SOLUTION
Avatar of kaufmed
kaufmed
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
GetProperties will only return properties, not fields (you will get the field values from their associated properties if the property defines a get method).  If you need the fields, you must use GetFields with the appropriate binding flags.  In 99.9% of all cases the following binding flags parameters will suffice:
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static

Open in new window

-saige-
I'm walking through it.  I am getting the property.name.  When I get the value I receive the below error.

'(property.GetValue(s) ?? null).ToString()' threw an exception of type 'System.Reflection.TargetException'
    Data: {System.Collections.ListDictionaryInternal}
    HResult: -2146232829
    HelpLink: null
    InnerException: null
    Message: "Object does not match target type."
    Source: "mscorlib"
    StackTrace: "   at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)\r\n   at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\r\n   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)\r\n   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)\r\n   at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)\r\n   at System.Reflection.PropertyInfo.GetValue(Object obj)"
    TargetSite: {Void CheckConsistency(System.Object)}
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks.  That helped a lot.
Line 12 in both offerings should be (the string "null", not the operator):

object value = (property.GetValue(m_source) ?? "null").ToString();

Open in new window


@it_saige

Good catch. I was hand-coding that one in TextPad, so I didn't catch that bit.