I want to create a property of a class, and set the name of that property using a variable value.
E.g.
string resultValue = "stack";
MyClass myclass = new MyClass();
myclass.resultValue = "overflow";
Now here in this case, stack is the property name and "overflow" is the value of the stack property.
Please tell how is it possible.
Thanks in advance.
You could use Reflection. For example:
string name = "stack";
string value = "overflow";
PropertyInfo pi = typeof(MyClass).GetProperty(name);
MyClass instance = new MyClass();
pi.SetValue(instance, value, null);
// at this stage instance.stack equals to "overflow"
This obviously assumes that MyClass has a public property stack with a public setter:
public class MyClass
{
public string stack { get; set; }
}
You should use Reflection for this
MyClass myclass = new MyClass();
Type type = typeof(MyClass);
PropertyInfo property = type.GetProperty("stack");
property.SetValue(myclass, "overflow", null);
I think that the Dynamic Source Code Generation and Compilation section on MSDN should contain the information you need.
The .NET Framework includes a mechanism called the Code Document
Object Model (CodeDOM) that enables developers of programs that emit
source code to generate source code in multiple programming languages
at run time, based on a single model that represents the code to
render.
I think that you could also get this done using Reflection.
Maybe you should take a look at DynamicObject. With this you can create properties at runtime by simply assigning a value. An example can also be found at the MSDN article.
Have at look at Mark Gravell's FastMember
It allows you to set properties in a dynamic manner.
// obj could be static or DLR
var wrapped = ObjectAccessor.Create(obj);
string propName = // something known only at runtime
FastMember Blog Post
I can't imagine why you want to generate property on your class, but consider other ways. E.g. using Dictionary:
class MyClass
{
Dictionary<string, object> _values = new Dictionary<string, object>();
public object this[string name]
{
get
{
if (!_values.ContainsKey(name))
throw new ArgumentException(name);
return _values[name];
}
set
{
if (!_values.ContainsKey(name))
{
_values.Add(name, value);
return;
}
_values[name] = value;
}
}
}
Usage:
MyClass myClass = new MyClass();
myClass["stack"] = "overflow";
Console.WriteLine(myClass["stack"]);
As far as I know, is this not possible. You can try using a dictionary.
Related
I have a "settings" class, which has some properties for usability and to restrict set accessor. It seems easy while i had within ten items, but then their count was increased. I need some way to create these properties automatically, something like that:
foreach(var property in SettingsList)
{
_settings.AddAutoProperty(property);
}
It may have deal with reflection, but i can't get to efficient solution.
The properties definition:
public bool cbNextExcCount
{
get { return (bool)this.GetValueById("cbNextExcCount"); }
}
public bool cbSaveOnChangeExc
{
get { return (bool)this.GetValueById("cbSaveOnChangeExc"); }
}
public bool cbAutoIncrement
{
get { return (bool)this.GetValueById("cbAutoIncrement"); }
}
public bool cbRememberOnExit
{
get { return (bool)this.GetValueById("cbRememberOnExit"); }
}
...etc.
UPDATE
To summ up, i wrote the next code:
public IDictionary<string, object> Properties = new ExpandoObject();
private List<string> SettingsList = new List<string>
{
"cbNextExcCount",
"cbSaveOnChangeExc",
"cbAutoIncrement",
"cbRememberOnExit"
};
public void CreateProperties()
{
foreach (string SettingName in SettingsList)
{
Properties.Add(SettingName, () => this.GetValueById(SettingName));
}
}
But i have an error on () => this.GetValueById("cbNextExcCount")):
argument type 'lambda expression' is not assignable to parameter type 'object'.
I can store Func<bool>, but settings may have other type than bool and if i use Func, it's get a bit more complicate to call.
You can't create auto-properties, but you can use an ExpandoObject.
I'm not sure if this is what you're looking for, because using expandos means using duck typing (i.e. dynamic programming).
ExpandoObject sample:
dynamic expando = new ExpandoObject();
expando.PropertyA = "Hello";
expando.PropertyB = "world!";
An interesting thing about expandos is that ExpandoObject implements IDictionary<string, object>, meaning that you can upcast any expando to this type and iterate over its added properties, which could be great for storing run-time created settings.
UPDATE
I was thinking more about a good solution and if SettingList is a custom class developed by yourself, maybe you can add a property called Custom to SettingList and add there settings that aren't added during design-time.
UPDATE 2
In your case, instead of storing the actual value of something, you could add Func<bool> to ExpandoObject's run-time settings:
IDictionary<string, object> settings = new ExpandoObject();
settings.Add("cbNextExcCount", () => this.GetValueById("cbNextExcCount"));
Actually, I don't know this scope in your code sample, but change this to anything that could be an instance of SettingList or whatever.
Once you've added run-time settings, you can type settings variable to dynamic typing in order to access properties like this:
dynamic allSettings = (dynamic)settings;
bool cbNextExcCount = allSettings.cbNextExcCount();
You can consider Expando Objects in System.Dynamic namespace. This article can be a good start.
I want to be able to access property values in an object like a dictionary, using the name of the property as a key. I don't really care if the values are returned as objects, so Dictionary<string, object> is fine. This is the intended usage:
object person = new { Name: "Bob", Age: 45 };
IDictionary<string, object> lookup = new PropertyDictionary(person);
string name = (string)person["Name"];
person["Age"] = (int)person["Age"] + 1; // potentially editable
I was about to implement my own class for this, but then I started noticing classes like DynamicObject implement the IDictionary interface, which made think this was already being done for me somewhere.
What I want is similar to the functionality used by ASP.NET MVC that allows using anonymous types to set HTML tag attributes. I have a lot of classes that use dictionaries as data sources, but most of the time I should be able to pass in objects as well.
Since this is for a general-purpose library, I thought I would create a reusable class that simply decorated an object with the IDictionary interface. It will save me from creating an explosion of overloads.
I don't believe there is a built-in .Net type like this already in the .Net framework. It seems like you really want to create an object that behaves a lot like a Javascript object. If so then deriving from DynamicObject may be the right choice. It allows you to create an object which when wrapped with dynamic allows you to bind directly obj.Name or via the indexer obj["Name"].
public class PropertyBag : DynamicObject {
private object _source;
public PropertyBag(object source) {
_source = source;
}
public object GetProperty(string name) {
var type = _source.GetType();
var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
return property.GetValue(_source, null);
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
result = GetProperty(binder.Name);
return true;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
result = GetProperty((string)indexes[0]);
return true;
}
}
You can use this to wrap any type and use both the indexer and name syntax to get the properties
var student = new Student() { FirstName = "John", LastName = "Doe" };
dynamic bag = new PropertyBag(student);
Console.WriteLine(bag["FirstName"]); // Prints: John
Console.WriteLine(bag.FirstName); // Prints: John
I have this extension method, probably the simplest it can get:
public static Dictionary<string, object> ToPropertyDictionary(this object obj)
{
var dictionary = new Dictionary<string, object>();
foreach (var propertyInfo in obj.GetType().GetProperties())
if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0)
dictionary[propertyInfo.Name] = propertyInfo.GetValue(obj, null);
return dictionary;
}
Now you can do:
object person = new { Name = "Bob", Age = 45 };
var lookup = person.ToPropertyDictionary();
string name = (string)lookup["Name"];
lookup["Age"] = (int)lookup["Age"] + 1; // indeed editable
Note:
that this dictionary is case-sensitive (you can trivially extend it passing the right StringComparer).
that it ignores indexers (which are also properties) but it's up to you to work on it.
that the method is not generic considering it doesn't help boxing because internally it calls obj.GetType, so it boxes anyway at that point.
that you get only the "readable" properties (otherwise you dont get the values held in it). Since you want it to be "writable" as well then you should use CanWrite flag as well.
dynamic keyword may be one option for you. it uses dynamic language runtime. At runtime, it tries to match the closest available type in the program. If it cant, then it converts the dynamic type to dictionay object, where key is the name of property and value is the value of property.
follow these links of MSDN:
Using dynamic keyword in C#
dynamic (C# Reference)
DLR Overview
usage of dynamic sample walkthough page
I want to get value for a dynamic property of a dynamic object.
Here is my Code..
public string ReturnProperty(object ob, string prop)
{
Type type = ob.GetType();
PropertyInfo pr = type.GetProperty(prop);
//Here pr is null..Dont know whats wrong
return pr.GetValue(ob, null).ToString();
}
My guess is that either it isn't a public property, or you've got the name wrong, or it isn't a property at all (but a public field).
It's impossible to say more without knowing what the actual type is, but that should be a start.
You mention that this is a "dynamic object" but that's not really very descriptive. Bear in mind that the CLR itself doesn't know anything about the DLR - if you mean this is a type which implements IDynamicMetaObjectProvider or extends DynamicObject, then you won't be able to get at the properties with "normal" reflection like this.
In my case ob did not have pr getter setter properly.
//causes GetProperty to return null
public class MyClass{
public object pr;
}
//Works
public class MyClass{
public object pr { get; set; }
}
In my case, I had to define get and set. See post above
public string MyPropertyName { get; set; }
After this I could get the property by:
typeof(MyClassItem).GetProperty("PropertyName")
If the item you are attempting to access doesn't have getter and setter accessors, then most likely it is a field.
So your code would work as follows:
FieldInfo fieldInfo = type.GetField(fieldName);
Try the Type.GetProperty(String, BindingFlags) overload and select the right binding flags.
Example for ExpandoObject(it implements IDynamicMetaObjectProvider Jon Skeet mentioned):
public static string ReturnProperty(object ob, string prop)
{
if (ob is ExpandoObject)
{
return ((ExpandoObject)ob).Single(e => e.Key == prop).Value.ToString();
}
Type type = ob.GetType();
PropertyInfo pr = type.GetProperty(prop);
return pr.GetValue(ob, null).ToString();
}
//--
dynamic dyna = new ExpandoObject();
dyna.Name = "Element";
Console.WriteLine(ReturnProperty(dyna, "Name"));
I had the same error, the problem lies in the field names, if you have a field to read from the sql "isField" and its class has a field is named "IsField". The compiler will read case sensitive , for all reason it's a different field, for that reason you have null. Check yours casesensitive fields nomenculature.
I was trying to access a public property, but I was using BindingFlags.NonPublic instead of BindingFlags.Public.
I tried this & it worked.
public string ReturnProperty(object ob, string prop)
{
Type type = ob.GetType();
PropertyInfo pr = type.GetProperty(prop);
//Here pr is null..Dont know whats wrong
return pr.GetValue(ob, null).ToString();
}
ReturnProperty(new { abc = 10 }, "abc");
Whats wrong???
I just came across this issue when I was passing in the wrong data of a sorted grid view in an MVC project.
public HolidaysGridViewModel()
{
this.Sort = "HolidayDate"; // this was the wrong name
this.SortDir = "ASC";
}
It made me realize after reading your question that you were most likely passing in the name of a business from the database instead of the name of the database column object and therefore no were results were found which may have been the cause of your null value.
i've some classes and want to access their properties using index or something like
ClassObject[0] or better will be ClassObject["PropName"]
instead of this
ClassObj.PropName.
Thanks
You need indexers:
http://msdn.microsoft.com/en-us/library/aa288465(v=vs.71).aspx
public class MyClass
{
private Dictionary<string, object> _innerDictionary = new Dictionary<string, object>();
public object this[string key]
{
get { return _innerDictionary[key]; }
set { _innerDictionary[key] = value; }
}
}
// Usage
MyClass c = new MyClass();
c["Something"] = new object();
This is notepad coding, so take it with a pinch of salt, however the indexer syntax is correct.
If you want to use this so you can dynamically access properties, then your indexer could use Reflection to take the key name as a property name.
Alternatively, look into dynamic objects, specifically the ExpandoObject, which can be cast to an IDictionary in order to access members based on literal string names.
You can do something like this, a pseudocode:
public class MyClass
{
public object this[string PropertyName]
{
get
{
Type myType = typeof(MyClass);
System.Reflection.PropertyInfo pi = myType.GetProperty(PropertyName);
return pi.GetValue(this, null); //not indexed property!
}
set
{
Type myType = typeof(MyClass);
System.Reflection.PropertyInfo pi = myType.GetProperty(PropertyName);
pi.SetValue(this, value, null); //not indexed property!
}
}
}
and after use it like
MyClass cl = new MyClass();
cl["MyClassProperty"] = "cool";
Note that this is not complete solution, as you need to "play" with BindingFlags during reflection access if you want to have non public properties/fields, static ones and so on.
public string this[int index]
{
get
{ ... }
set
{ ... }
}
This will give you an indexed property. You can set any parameter you wish.
I'm not sure what you mean here, but I'll say that you have to make ClassObject some sort of IEnumirable type, like List<> or Dictionary<> to use it the way to aim for here.
I have a class with a static factory method on it. I want to call the factory to retrieve an instance of the class, and then do additional initialization, preferablly via c# object initializer syntax :
MyClass instance = MyClass.FactoryCreate()
{
someProperty = someValue;
}
vs
MyClass instance = MyClass.FactoryCreate();
instance.someProperty = someValue;
No. Alternatively you could accept a lambda as an argument, which also gives you full control in which part of the "creation" process will be called. This way you can call it like:
MyClass instance = MyClass.FactoryCreate(c=>
{
c.SomeProperty = something;
c.AnotherProperty = somethingElse;
});
The create would look similar to:
public static MyClass FactoryCreate(Action<MyClass> initalizer)
{
MyClass myClass = new MyClass();
//do stuff
initializer( myClass );
//do more stuff
return myClass;
}
Another option is to return a builder instead (with an implicit cast operator to MyClass). Which you would call like:
MyClass instance = MyClass.FactoryCreate()
.WithSomeProperty(something)
.WithAnotherProperty(somethingElse);
Check this for the builder
Both of these versions are checked at compile time and have full intellisense support.
A third option that requires a default constructor:
//used like:
var data = MyClass.FactoryCreate(() => new Data
{
Desc = "something",
Id = 1
});
//Implemented as:
public static MyClass FactoryCreate(Expression<Func<MyClass>> initializer)
{
var myclass = new MyClass();
ApplyInitializer(myclass, (MemberInitExpression)initializer.Body);
return myclass ;
}
//using this:
static void ApplyInitializer(object instance, MemberInitExpression initalizer)
{
foreach (var bind in initalizer.Bindings.Cast<MemberAssignment>())
{
var prop = (PropertyInfo)bind.Member;
var value = ((ConstantExpression)bind.Expression).Value;
prop.SetValue(instance, value, null);
}
}
Its a middle between checked at compile time and not checked. It does need some work, as it is forcing constant expression on the assignments. I think that anything else are variations of the approaches already in the answers. Remember that you can also use the normal assignments, consider if you really need any of this.
Yes. You can use object initializer for already created instance with the following trick. You should create a simple object wrapper:
public struct ObjectIniter<TObject>
{
public ObjectIniter(TObject obj)
{
Obj = obj;
}
public TObject Obj { get; }
}
And now you can use it like this to initialize your objects:
new ObjectIniter<MyClass>(existingInstance)
{
Obj =
{
//Object initializer of MyClass:
Property1 = value1,
Property2 = value2,
//...
}
};
P.S. Related discussion in dotnet repository:
https://github.com/dotnet/csharplang/issues/803
You can use an extension method such as the following:
namespace Utility.Extensions
{
public static class Generic
{
/// <summary>
/// Initialize instance.
/// </summary>
public static T Initialize<T>(this T instance, Action<T> initializer)
{
initializer(instance);
return instance;
}
}
}
You would call it as follows:
using Utility.Extensions;
// ...
var result = MyClass.FactoryCreate()
.Initialize(x =>
{
x.someProperty = someValue;
x.someProperty2 = someValue2;
});
+1 on "No".
Here's an alternative to the anonymous object way:
var instance = MyClass.FactoryCreate(
SomeProperty => "Some value",
OtherProperty => "Other value");
In this case FactoryCreate() would be something like:
public static MyClass FactoryCreate(params Func<object, object>[] initializers)
{
var result = new MyClass();
foreach (var init in initializers)
{
var name = init.Method.GetParameters()[0].Name;
var value = init(null);
typeof(MyClass)
.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
.SetValue(result, value, null);
}
return result;
}
No, the object initializer can only be used on a call to "new" with the constructor. One option might be to add some additional args to your factory method, to set those values at object creation inside the factory.
MyClass instance = MyClass.FactoryCreate(int someValue, string otherValue);
Like everyone said, no.
A lambda as an argument has already been suggested.
A more elegant approach would be to accept an anonymous and set the properties according to the object. i.e.
MyClass instance = MyClass.FactoryCreate(new {
SomeProperty = someValue,
OtherProperty = otherValue
});
That would be much slower though, since the object would have to be reflected on for all the properties.
No, that's something you can only do 'inline'. All the factory function can do for you is to return a reference.