I have a class:
namespace TestLib1
public class TestLib1
{
public IEnumerable<TestedParameter> Measure1(IEnumerable<TestedParameter> _inParameters)
{ // this is just to do something
foreach (TestedParameter item in _inParameters)
{
item.Param_Description = "TestParam";
}
return _inParameters;
}
}
that contains class from
public class Acceptance_Criteria
{
private double _lowest;
private double _highest;
public bool Compare(double _verifiedValue)
{
if ((_verifiedValue >= _lowest) && (_verifiedValue <= _highest))
{
return true;
}
else
{
return false;
}
}
public double Acceptance_Lowest { get =>_lowest;set =>_lowest = value; }
public double Acceptance_Highest {get=>_highest;set =>_highest = value; }
}
public class TestedParameter : Acceptance_Criteria
{
private string _param_Description;
private double _value;
private string _units;
private bool _value_matches_acceptance_critera;
private bool _value_checked_against_criteria;
private string pass_fail_reason;
public string Param_Description { get => _param_Description; set => _param_Description = value; }
public double Value { get => _value; set => _value = value; }
public string Units { get => _units; set => _units = value; }
public bool Value_matches_acceptance_critera { get => _value_matches_acceptance_critera; set => _value_matches_acceptance_critera = value; }
public bool Value_checked_against_criteria { get => _value_checked_against_criteria; set => _value_checked_against_criteria = value; }
public string Pass_fail_reason { get => pass_fail_reason; set => pass_fail_reason = value; }
}
and I placed TestLib in DLL and call it from other file :
Assembly SampleAssembly = Assembly.LoadFrom("TestLib1.dll");
Type[] types2 = SampleAssembly.GetTypes();//e
Type SearchedType = null;
foreach (Type type in types2)
{
if (type.FullName.Contains("TestLib1.TestLib1")) { SearchedType = SampleAssembly.GetType(type.FullName); }
}
if (SearchedType != null)
{
MethodInfo Method = SearchedType.GetMethod("Measure1");
if (Method != null)
{
object result = null;
ParameterInfo[] parameters = Method.GetParameters();
object classInstance = Activator.CreateInstance(SearchedType, null);
if (parameters.Length == 0)
{
//This works fine
result = Method.Invoke(classInstance, null);
}
else
{
List<TestedParameter> parametersIn = new List<TestedParameter>();
TestedParameter param1 = new TestedParameter();
param1.Param_Description = "testparam1"; // GET NAME FROM XML
parametersIn.Add(param1);
IEnumerable<TestedParameter> enumarableList = parametersIn.AsEnumerable();
object[] parametersArrayx = new object[] { enumarableList };
object resx = Method.Invoke(classInstance, parametersArrayx.ToArray());
List<TestedParameter> res = (List<TestedParameter>)resx;
}
}
}
When I execute Method.Invoke
I get thie exception:
System.ArgumentException:
'Object of type 'System.Collections.Generic.List`1[WindowsFormsApp1.TestedParameter]'
cannot be converted to type 'System.Collections.Generic.List`1[WindowsFormsApp1.TestedParameter]'.'
I also tried to push parametersArrayx without ToArray() but it also didnt work
Can anyone look a the code a let me know what do I do wrong ?
I want to execute code from DLL lib with list of parameters pushed (later I want to import those parameters from XML file.)
Thank You :)
SearchedType.GetMethod("Measure1");
convert to
SearchedType.GetMethod("Measure1", new Type[] { typeof(List<Filter>) });
Related
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);
}
}
}
}
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;
}
I'd like to get a string representation given a property. This way I can use this string for NotifyPropertyChanged and stil be ok after a refactoring of the property's name.
EDIT: I'm using .NET 4.0
UPDATE: I'd also like to have the name available for DependencyProprtys, i.e. I need the value during static variable assignment time.
Same sample code to explain:
// actual code
private int prop = 42;
public int Prop
{
get
{
return prop;
}
set
{
prop = value;
NotifyPropertyChanged("Prop"); // I'd like to replace the hard-coded string here
}
}
// code as I'd like it to be
private int propNew = 42;
private static readonly string PropNewName = GainStringFromPropertySomeHow(PropNew); // should be "PropNew"
public int PropNew
{
get
{
return propNew;
}
set
{
propNew = value;
NotifyPropertyChanged(PropNewName); // <== will remain correct even if PropNew name is changed
}
}
After refactoring:
private int prop = 42;
public int PropNameChanged
{
get
{
return prop;
}
set
{
prop = value;
NotifyPropertyChanged("Prop"); // oops
}
}
private int propNew = 42;
private static readonly string PropNewName = GainStringFromPropertySomeHow(PropNewNameChanged); // should be "PropNewNameChanged"
public int PropNewNameChanged
{
get
{
return propNew;
}
set
{
propNew = value;
NotifyPropertyChanged(PropNewName); // still correct
}
}
I think this could be helpfull:
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Source and more explanation: http://msdn.microsoft.com/de-de/library/system.componentmodel.inotifypropertychanged.aspx
And here:
http://msdn.microsoft.com/de-de/library/system.runtime.compilerservices.callermembernameattribute.aspx
If you're not yet on .Net 4.5 and thus cannot use CallerMemberName, you can use this approach: https://stackoverflow.com/a/3191598/869250
This is a duplicate of How to get current property name via reflection?
So you can just do this
NotifyPropertyChanged(MethodBase.GetCurrentMethod().Name);
I found a solution here on Stackoverflow:
https://stackoverflow.com/a/672212/1254743
and
https://stackoverflow.com/a/2820759/1254743
The resulting code:
public static class PropertyNameExtractor
{
/// <summary>
/// Usage: PropertyNameExtractor.ExposeProperty(() => this.YourProperty)
/// yields: "YourProperty"
/// </summary>
public static string ExposeProperty<T>(Expression<Func<T>> property)
{
var expression = GetMemberInfo(property);
return expression.Member.Name;
}
private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null)
throw new ArgumentNullException("method");
MemberExpression memberExpr = null;
if (lambda.Body.NodeType == ExpressionType.Convert)
{
memberExpr =
((UnaryExpression)lambda.Body).Operand as MemberExpression;
}
else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpr = lambda.Body as MemberExpression;
}
if (memberExpr == null)
throw new ArgumentException("method");
return memberExpr;
}
}
In my class:
class MyClass: INotifyPropertyChanged
{
public MyClass()
{
this.nameOf_MyProperty = PropertyNameExtractor.ExposeProperty(() => this.MyProperty);
}
private readonly string nameOf_MyProperty;
private int myProperty = 42 ;
public int MyProperty
{
get
{
return myProperty;
}
set
{
myProperty= value;
NotifyPropertyChanged(nameOf_MyProperty);
}
}
private void NotifyPropertyChanged(String PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
I have been working with a project for last 4 months. We are using a custom framework for the development. The problem I am talking about, was working for all other classes. But for the first time I am facing this weird incident. Now Straight to break point.
My framework code is like
public static List<ViewNotSetBillableCoursesEntity> GetAllNotSetBillableCources()
{
try
{
List<ViewNotSetBillableCoursesEntity> entities = new List<ViewNotSetBillableCoursesEntity>();
string command = SELECT;
SqlConnection sqlConnection = MSSqlConnectionHandler.GetConnection();
SqlDataReader dataReader = QueryHandler.ExecuteSelect(command, sqlConnection);
entities = Maps(dataReader);
dataReader.Close();
return entities;
}
catch (Exception exception)
{
throw exception;
}
}
In the above method the dataReader is sent to Maps method.
The Maps method is ......
private static List<ViewNotSetBillableCoursesEntity> Maps(SqlDataReader theReader)
{
SQLNullHandler nullHandler = new SQLNullHandler(theReader);
// the incident is happening here, the SQLNullHandler is given below.
List<ViewNotSetBillableCoursesEntity> entities = null;
while (theReader.Read())
{
if (entities == null)
{
entities = new List<ViewNotSetBillableCoursesEntity>();
}
ViewNotSetBillableCoursesEntity entity = Mapper(nullHandler);
entities.Add(entity);
}
return entities;
}
The SQLNullHandler is given below:
puplic Class SQLNullHandler
{
private IDataReader _reader;
public SQLNullHandler(IDataReader reader)
{
_reader = reader;
}
#region Get Null value
public static object GetNullValue(int Value)
{
if(Value==0)
{
return null;
}
else
{
return Value;
}
}
public static object GetNullValue(double Value)
{
if (Value == 0)
{
return null;
}
else
{
return Value;
}
}
public static object GetNullValue(decimal Value)
{
if (Value == 0)
{
return null;
}
else
{
return Value;
}
}
public static object GetNullValue(DateTime Value)
{
if(DateTime.MinValue==Value)
{
return null;
}
else
{
return Value;
}
}
public static object GetNullValue(string Value)
{
if(Value.Length<=0)
{
return null;
}
else
{
return Value;
}
}
#endregion
public IDataReader Reader
{
get{return _reader;}
}
public bool IsNull(int index)
{
return _reader.IsDBNull(index);
}
public int GetInt32(int i)
{
return _reader.IsDBNull(i)? 0 : _reader.GetInt32(i);
}
public byte GetByte(int i)
{
return _reader.IsDBNull(i)? (byte)0 : _reader.GetByte(i);
}
//and so on for all possible type for this app
}
The Funny thing is for all these classes these methods and lines of code work very fine, but in this scenario after the line SQLNullHandler nullHandler = new SQLNullHandler(theReader); the datareder becomes empty.
My questions are
Why is this Happening and next,
what can be done to solve this problem?
I need to call SetSettings() and using the 3 elements in splitSettings, set EncodeAudio to False.
How would I go about doing that? Convert the property of a object to who's name I have in a string.
I realize I could do with with a switch statement of all my settings but there has to be a more dynamic way to go about doing this.
namespace SettingsLib
{
public class Settings
{
public Boolean EncodeAudio { get; set; }
}
}
namespace Service
{
void SetSettings()
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
// Need to set EncodeAudio to False in SettingsLib.Settings
}
}
Yes I have a instance of Settings
Say:
Settings settingManager = new Settings();
I am trying to do is dynamically set EncodeAudo to False by using elements of splitSettings
settingManager.EncodeAudio = False;
Thanks to the help of TBohnen.jnr
I came to this answer:
public void setProperty(object containingObject, string propertyName, object newValue)
{
foreach (PropertyInfo p in containingObject.GetType().GetProperties())
{
if (p.Name == propertyName)
{
p.SetValue(containingObject, Convert.ChangeType(newValue, p.PropertyType), null);
}
}
}
EDIT Tested it with int, bool, double and string and it worked, also added a check to make sure that the property exists and throws an exception of it doesn't (Might want to change Exception type)
EDIT 2: Temporary solution, will add more typenames to the convert method or alternatively if somebody can suggest a more dynamic way of casting it (If not then I assume you will have to know all of the types that will be used)?
EDIT3 Stole the convert method from another answer in question (Chris Taylor ), thanks :-)
public void setProperty(object containingObject, string propertyName, object newValue)
{
if (containingObject.GetType().GetProperties().Count(c => c.Name == propertyName) > 0)
{
var type = containingObject.GetType().GetProperties().First(c => c.Name == propertyName).PropertyType;
object val = Convert(type,(string)newValue);
containingObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, containingObject, new object[] { val });
}
else
{
throw new KeyNotFoundException("The property: " + propertyName + " was not found in: " + containingObject.GetType().Name);
}
}
public object convert(System.Type type, string value)
{
return Convert.ChangeType(value, type);
}
Taken from http://www.haslo.ch/blog/setproperty-and-getproperty-with-c-reflection/
Was interested to see if this works, create a quick test:
class testSettings
{
public bool SetBool { get; set; }
public void setProperty(object containingObject, string propertyName, object newValue)
{
if (containingObject.GetType().GetProperties().Count(c => c.Name == propertyName) > 0)
{
containingObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, containingObject, new object[] { newValue });
}
else
{
throw new KeyNotFoundException("The property: " + propertyName + " was not found in: " + containingObject.GetType().Name);
}
}
}
static void Main(string[] args)
{
testSettings ts = new testSettings();
ts.SetBool = false;
ts.setProperty(ts, "SetBool", true);
Console.WriteLine(ts.SetBool.ToString());
Console.Read();
}
The output is true, not entirely sure if it will convert all types correctly though.
As others have mentioned, you should consider making your SettingsLib class static. And you might also need to handle the conversion of values from strings to the target types. Here is a simple example how this would work.
namespace Service
{
class Program
{
static void Main(string[] args)
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
SetProperty(splitSettings[0], splitSettings[1], splitSettings[2]);
}
static void SetProperty(string typeName, string propertyName, object value)
{
var type = Type.GetType(typeName);
if (type == null)
{
throw new ArgumentException("Unable to get type", "typeName");
}
var pi = type.GetProperty(propertyName);
if (pi == null)
{
throw new ArgumentException("Unable to find property on type", "propertyName");
}
object propertyValue = value;
if (propertyValue != null)
{
// You might need more elaborate testing here to ensure that you can handle
// all the various types, you might need to special case some types here
// but this will work for the basics.
if (pi.PropertyType != propertyValue.GetType())
{
propertyValue = Convert.ChangeType(propertyValue, pi.PropertyType);
}
}
pi.SetValue(null, propertyValue, null);
}
}
}
namespace SettingsLib
{
public static class Settings
{
public static bool EncodeAudio { get; set; }
}
}
Maybe you should mark your settable properties as static and then try to set the values using Reflection:
namespace SettingsLib
{
public static class Settings
{
public static bool EncodeAudio { get; set; }
}
}
namespace Service
{
void SetSettings()
{
string[] splitSettings = { "SettingsLib.Settings", "EncodeAudio", "False" };
dynamic property = Type.GetType(splitSettings[0]).GetProperty(splitSettings[1]);
property = splitSettings[2];
}
}