I am in need of creating a dynamically extend-able class in C#.
The goal is to create a class what can contain all info from a given contact from an Android SQLite Contacts table. The table's structure is kinda weird, as it does not have set field names, but uses colums of 'field name' and 'field content'.
That's what I want to turn into a usable format where the code reads the database, and for each entry creates the matching sub-variable. Such I want to know the best method to do so (I guess a simple
{
this.(variableNames[i].ToString()) = variableContent[i];
}
will not do it), what is the least resource-eating, but fastest (and easiest) way.
And also if we are here, is there ANY method to call a type's (let's say, I create a new Contact with e-mail, workplace, name, and image tags, but these variables names' are unknown) ALL sub-variables (Contact.image, Contact.FirstName, Contact.Email, etc) dynamically?
Of course there will be standardized fields what should be in ALL contact (one of the three names, phone number, e-mail #work and #home, and such), but these should be called dynamically too.
Use a Dictionary<string,string> instead.
Dictionary<string,string> contactInfo = new Dictionary<string,string>();
public void ImportContact()
{
...
// for each fieldName and fieldValue from your table
contactInfo.Add(fieldName, fieldValue);
...
// check that all standard fields are present, if desired
}
public string FirstName
{
get { return contactInfo["FirstName"]; }
}
If you are willing to go with dynamic typing, you can use the dynamic type in C# 4. You can use ExpandoObject or DynamicObject as a base for your Contact types.
Here is an example of a Contact class that can work both statically typed with some pre-defined properties; and can have properties attached to it at run-time. When treating it statically, you can still get the values by using the indexer:
class Contact : DynamicObject
{
private readonly Dictionary<string, object> bag = new Dictionary<string, object>();
public string FirstName { get; set; }
public string LastName { get; set; }
public object this[string key]
{
get { return bag[key]; }
set { bag[key] = value; }
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (bag.ContainsKey(binder.Name))
{
result = bag[binder.Name];
return true;
}
return base.TryGetMember(binder, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
bag[binder.Name] = value;
return true;
}
}
Which you can then use like this:
// Contact is statically typed.
Contact c = new Contact();
c.FirstName = "test";
// Treat as dynamic and attach some extra properties:
dynamic dynContact = c;
dynContact.AddressOne = "Somewhere";
dynContact.AddressTwo = "Someplace else";
Console.WriteLine(dynContact.AddressOne);
Console.WriteLine(dynContact.AddressTwo);
Other than using dynamic, you cannot create a new class with dynamically typed properties. After all, how would you consume those properties ? You might be better off creating a class containing the properties that you must have; and put the rest in a Dictionary<string,object>.
If you're using .NET 4.0, there's dynamic support. You can create objects something like this:
var newContact = new object { FirstName = "name", LastName = "name", etc... };
Alternatively, you might want to try using a Dictionary.
Related
I have a WebAPI service where I would like to allow users to specify which fields they'd like returned. For example, say I have the following Person class:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
and that calling /api/people/ returns all three fields for all people. How do I handle a request like /api/people?fields=FirstName,Email returning just those two fields for all people? Bonus points if I can map something like first_name to FirstName but that's not required.
This is a job for the Dynamic Language Runtime and specifically ExpandoObject, whereby you return only the properties you need as determined at runtime:
public dynamic GetPerson()
{
bool firstNameRequired = true; // TODO: Parse querystring
bool lastNameRequired = false; // TODO: Parse querystring
dynamic rtn = new ExpandoObject();
if (firstNameRequired)
rtn.first_name = "Steve";
if (lastNameRequired)
rtn.last_name = "Jobs";
// ... and so on
return rtn;
}
void Main()
{
// Using the serializer of your choice:
Console.WriteLine(Newtonsoft.Json.JsonConvert.SerializeObject(GetPerson()));
}
Output:
{"first_name":"Steve"}
I don't have the means to test it right now [I have something similar in production on vanilla Web API, with a large number of optional fields], but going by the .NET Core docs the web method would look something like this albeit without the hard coded values!:
[HttpGet()]
public IActionResult Get([FromQuery(Name = "fields")] string fields)
{
var fieldsOptions = fields.Split(',');
dynamic rtn = new ExpandoObject();
if (fieldsOptions.Contains("FirstName"))
rtn.first_name = "Steve";
if (fieldsOptions.Contains("LastName"))
rtn.last_name = "Jobs";
if (fieldsOptions.Contains("Email"))
rtn.email = "steve#apple.com";
return new ObjectResult(rtn);
}
You would need to reference the System.Dynamic.Runtime package.
You can use conditional serialization. You will just base your ShouldSerialize return value on whether or not the fields parameter contains the string identifying that field. This will work for whatever string(s) you want to associate with the field. You can even accept multiple strings for each field, if you want to.
To get the fieldList into the object you want to serialize (Person), you can just pass it or something that contains it (HttpRequest.Query or some custom Options class) into the constructor.
public bool ShouldSerializeFirstName(){
return fieldList.Contains("FirstName");
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Finding the Variable Name passed to a Function in C#
The class below contains the field city.
I need to dynamically determine the field's name as it is typed in the class declaration
i.e. I need to get the string "city" from an instance of the object city.
I have tried to do this by examining its Type in DoSomething() but can't find it when examining the contents of the Type in the debugger.
Is it possible?
public class Person
{
public string city = "New York";
public Person()
{
}
public void DoSomething()
{
Type t = city.GetType();
string field_name = t.SomeUnkownFunction();
//would return the string "city" if it existed!
}
}
Some people in their answers below have asked me why I want to do this.
Here's why.
In my real world situation, there is a custom attribute above city.
[MyCustomAttribute("param1", "param2", etc)]
public string city = "New York";
I need this attribute in other code.
To get the attribute, I use reflection.
And in the reflection code I need to type the string "city"
MyCustomAttribute attr;
Type t = typeof(Person);
foreach (FieldInfo field in t.GetFields())
{
if (field.Name == "city")
{
//do stuff when we find the field that has the attribute we need
}
}
Now this isn't type safe.
If I changed the variable "city" to "workCity" in my field declaration in Person this line would fail unless I knew to update the string
if (field.Name == "workCity")
//I have to make this change in another file for this to still work, yuk!
{
}
So I am trying to find some way to pass the string to this code without physically typing it.
Yes, I could declare it as a string constant in Person (or something like that) but that would still be typing it twice.
Phew! That was tough to explain!!
Thanks
Thanks to all who answered this * a lot*. It sent me on a new path to better understand lambda expressions. And it created a new question.
Maybe you need this. Works fine.
I found this here.
static void Main(string[] args)
{
var domain = "matrix";
Check(() => domain);
Console.ReadLine();
}
static void Check<T>(Expression<Func<T>> expr)
{
var body = ((MemberExpression)expr.Body);
Console.WriteLine("Name is: {0}", body.Member.Name);
Console.WriteLine("Value is: {0}", ((FieldInfo)body.Member)
.GetValue(((ConstantExpression)body.Expression).Value));
}
Output will be:
Name is: 'domain'
Value is: 'matrix'
I know this is old question, but I was trying to achieve the same and google sent me here. After many hours I finally found a way. I hope somebody else will find this useful.
There are actually more ways to accomplish this:
static void Main(string[] args)
{
GetName(new { var1 });
GetName2(() => var1);
GetName3(() => var1);
}
static string GetName<T>(T item) where T : class
{
return typeof(T).GetProperties()[0].Name;
}
static string GetName2<T>(Expression<Func<T>> expr)
{
return ((MemberExpression)expr.Body).Member.Name;
}
static string GetName3<T>(Func<T> expr)
{
return expr.Target.GetType().Module.ResolveField(BitConverter.ToInt32(expr.Method.GetMethodBody().GetILAsByteArray(), 2)).Name;
}
The first is fastest. The last 2 are approx 20 times slower than the 1st one.
http://abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html
city in this case is an instance of type string. When you call .GetType() you return the actual string type, which has no knowledge at all of your particular city instance.
I'm having a hard time seeing why you can't just type "city" in the code as a string literal here, if that's what you need. Perhaps it would help if you shared what you want to use this value for and in what circumstances you will call your DoSomething() function.
At the moment, my best guess is that what you really want to do is reflect the entire Person class to get a list of the fields in that class:
public void DoSomething()
{
MemberInfo[] members = this.GetType().GetMembers();
// now you can do whatever you want with each of the members,
// including checking their .Name properties.
}
Okay, based on your edit I have some more for you.
You can find the name of fields that are decorated with your attribute at run-time like this:
Type t = typeof(Person);
foreach (MemberInfo member in t.GetMembers()
.Where(m =>
m.GetCustomAttributes(typeof(MyCustomAttribute)).Any() ) )
{
// "member" is a MemberInfo object for a Peson member that is
// decorated with your attribute
}
You can also use binding flags in the first GetMembers() call to limit it to just fields, if you want.
You mentioned "i.e. I need to get the string "city" from an instance of the object city."
Are you looking to get the field name from the value of the field.
For example:If there are 2 Person object one with city "New York" and the other with city "London", are you looking for the function to return "city". Is this what you mean by dynamic?
With your current design you will always need to compare the name of the field from the FieldInfo against a string.
What if you instead decouple this so that you hold the identifier to use for comparison purposes during reflection as part of the attribute.
Something like this:
public enum ReflectionFields
{
CITY = 0,
STATE,
ZIP,
COUNTRY
}
[AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
public class CustomFieldAttr : Attribute
{
public ReflectionFields Field { get; private set; }
public string MiscInfo { get; private set; }
public CustomFieldAttr(ReflectionFields field, string miscInfo)
{
Field = field;
MiscInfo = miscInfo;
}
}
public class Person
{
[CustomFieldAttr(ReflectionFields.CITY, "This is the primary city")]
public string _city = "New York";
public Person()
{
}
public Person(string city)
{
_city = city;
}
}
public static class AttributeReader<T> where T:class
{
public static void Read(T t)
{
//get all fields which have the "CustomFieldAttribute applied to it"
var fields = t.GetType().GetFields().Where(f => f.GetCustomAttributes(typeof(CustomFieldAttr), true).Length == 1);
foreach (var field in fields)
{
var attr = field.GetCustomAttributes(typeof(CustomFieldAttr), true).First() as CustomFieldAttr;
if (attr.Field == ReflectionFields.CITY)
{
//You have the field and you know its the City,do whatever processing you need.
Console.WriteLine(field.Name);
}
}
}
}
public class Program
{
public static void Main(string[] args)
{
PPerson p1 = new PPerson("NewYork");
PPerson p2 = new PPerson("London");
AttributeReader<PPerson>.Read(p1);
AttributeReader<PPerson>.Read(p2);
}
}
You can now freely rename _city field of Person to something else and your calling code will still work since the code using reflection is trying to identify the field using the ReflectionFields enum value set as part of initialization of the attribute set on the field.
Yes its possible !!!
Try this out...
public string DoSomething(object city)
{
return city.GetType().GetProperty("Name",typeof(string)).GetValue(city,null);
}
Two things here.
Number one, as someone above pointed out, you're getting the Type for string, not for Person. So typeof(Person).GetMembers() will get you the list of members.
Number two, and more importantly, it looks like you're misunderstanding the purpose of attributes. In general attributes are used to mark a member for specific processing or to add additional information. Here you're using the name to indicate what processing you want, and the attribute to specify parameters, which is mixing of metaphors, or something.
Abhijeet's answer is more appropriate, you mark the field as a city field, then do what you like with it. Where I disagree is that I would use different attribute classes, rather than an enumeration.
Something like:
public class MyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Field)]
public class MyCityAttribute : MyAttribute
{
}
[AttributeUsage(AttributeTargets.Field]
public class MyNameAttribute: MyAttribute
{
}
public class Person
{
[MyCity]
public string city = "New York";
[MyCity]
public string workCity = "Chicago";
[MyName]
public string fullName = "John Doe";
public Person()
{
}
public void DoSomething()
{
Type t = typeof(Person);
FieldInfo[] fields = t.GetFields(BindingFlags.Instance | BindingFlags.Public);
foreach (var field in fields)
{
MyAttribute[] attributes = field.GetCustomAttributes(typeof(MyAttribute));
if (attributes.Count > 0)
{
if (attributes[0] is MyCityAttribute)
{
//Dosomething for city
break;
}
if (attributes[0] is MyNameAttribute)
{
//Dosomething for names
break;
}
}
}
}
}
This would allow you to use different parameters for MyCity vs MyName that would make more sense in the context of processing each.
I think with your 'yuk' comment above, you hit the nail on the head. That you would have to change a string constant if you rename your variable is an indicator that you're doing something wrong.
t.GetField("city", BindingFlags.Public | BindingFlags.Instance);
or you can call GetFields() to get all fields
You need to call get type on the class Person. The iterate the fields of the class as in the answer below
This is not possible (I think it actually is but involes several hacks and using lambdas). If you want to store attributes about a Person and be able to get the name of the attribute easily, I suggest using a Dictionary<TKey, TValue> from the System.Collections.Generic namespace.
And you can always make public properties that wrap the dictionary.
public class Person
{
Dictionary<string, string> attributes = new Dictionary<string, string();
public string City
{
get { return attributes["city"]; }
set { attributes["city"] = value; }
}
public Person()
{
City = "New York";
}
}
And you can get a list of all attributes with attributes.Keys.
Have a look at this post as it looks similar to what you're trying to do:
Finding the variable name passed to a function
(especially Konrad Rudolph's answer) Another approach could be to just add "city" as one of the parameters in the attribute and fish that out later.
You are already looping through the collection of FieldInfo objects. Look for your attribute on those and when you find the FieldInfo that contains your attribute, you have the one you want. Then call .Name on it.
system.reflection.fieldinfo.attributes
I have a csv file where each row is a different type of record. I am parsing the csv and want to store the rows (varied types of records) in various types of custom classes.
At each row i need to instantiate a different class based on the record type.
So taken from other reflection examples, I have the code below;
Type type = Type.GetType("myNamespace." + className);
object recordclass = Activator.CreateInstance(type);
so i have an object named recordclass of the correct type, but how do I use it?
all I really want to do is access the properties of the class and populate the row data, and then later add to a container class.
I guess im missing something about the runtime nature of reflection. Please help me connect the dots!
Hope that all makes sense!
TIA,
Gary
With the example you give you could cast your object to the actual type you need:
Type type = Type.GetType("myNamespace." + className);
object recordclass = Activator.CreateInstance(type);
var record = recordClass as ConcreteRecordType;
if(record != null)
record.Name = csv["Name"];
Alternatively look into using a Factory to return populated record objects:
public class RecordFactory
{
RecordBase ParseCsvRow(string[] columns)
{
const int typeDescriminatorColumn = 0;
switch (columns[typeDescriminatorColumn])
{
case "RecordTypeA":
return new RecordTypeA(columns[1], columns[2], ...);
case "RecordTypeB":
return new RecordTypeB(columns[1], columns[2], ...);
default:
throw new InvalidOperationException("Unexpected descriminator: " + columns[typeDescriminatorColumn]);
}
}
}
If you want to store values into your recordclass's property via reflection use this
var property = type.GetProperty(propertyName);
property.SetValue(recordclass,value,null);
If you read the docs, you will see, Type.GetType requires a full qualified type name.
If I understand the problem correctly you have a file which contains text values for records. Each record is stored in a single line, and the start of each line is an identifier to say which kind of record is to be built.
It is possible to use reflection for this but not really neccessary. The problem with using reflection is that you need to know all the properties for the different record types in order to access them by name. At this point, you may as well be working with typed objects but if you are using the a single routine to create all the records (using CreateInstance()) all you have is an untyped object.
Another solution is to have a set of routines each of which take in, say an IEnumerable (the input line split by the comma, excluding the record id) and return an object (or a record, if you have a base record class) and use a factory to select which routine to use for each row.
You register the routines with the factory by some ID (the first field in the record as you are doing is good, it can be the record class name but doesn't have to be) and the iterate through the CSV lines, using the first piece to select the method from the factory and building the record.
Hopefully the example will explain a bit better :? Sorry about the volume of code
The builders in the example just return empty records but populating them from the row pieces should be easy. Another version is to just pass in the row, or a set of rows if a record can cover a number of rows (a but more complicated if the records take in different numbers of rows)
hth,
Alan.
public string[] Input = new[]{
"R1, F1, F2, F3",
"R2, F2, F4",
"R3, F2",
"R3, F2",
"R4, F1, F2, F3, F4"
};
public class RecordOne {
}
public class RecordTwo {
}
public class RecordThree {
}
public class RecordFour {
}
public class BuilderFactory {
public BuilderFactory() {
Builders = new Dictionary<string, Func<IEnumerable<string>, object>>();
}
private Dictionary<string, Func<IEnumerable<string>, object>> Builders { get; set; }
public void RegisterBuilder(string name, Func<IEnumerable<string>, object> builder) {
Builders.Add(name, builder);
}
public Func<IEnumerable<string>, object> GetBuilder(string name) {
return Builders[name];
}
}
[TestMethod]
public void LoadRecords() {
var factory = new BuilderFactory();
factory.RegisterBuilder("R1", BuildRecordOne);
factory.RegisterBuilder("R2", BuildRecordTwo);
factory.RegisterBuilder("R3", BuildRecordThree);
factory.RegisterBuilder("R4", BuildRecordFour);
var output = Input.Select(line => {
var pieces = line.Split(',').Select(val => val.Trim());
var builder = factory.GetBuilder(pieces.First());
return builder(pieces.Skip(1));
});
Assert.IsTrue(new[] {typeof(RecordOne),
typeof(RecordTwo),
typeof(RecordThree),
typeof(RecordThree),
typeof(RecordFour)}.SequenceEqual(output.Select(rec => rec.GetType())));
}
private static RecordOne BuildRecordOne(IEnumerable<string> pieces) {
return new RecordOne();
}
private static RecordTwo BuildRecordTwo(IEnumerable<string> pieces) {
return new RecordTwo();
}
private static RecordThree BuildRecordThree(IEnumerable<string> pieces) {
return new RecordThree();
}
private static RecordFour BuildRecordFour(IEnumerable<string> pieces) {
return new RecordFour();
}
I'm using var abc = new { id = 0 }; in my C# code without knowing what type it exactly is!
Is is simply called an object? Is it a particular type of object?
I want to know coz I don't know how to add fields to this kind of object
Quick example:
I have var abc = new { id = 0 }; and I want to add to abc the field name = "david"
It is an anonymous type, that is, it does not have a type that you can use in code (though the compiler generates one).
MSDN says:
The type name is generated by the compiler and is not available at the source code level.
If you want to add a property, you can simply do so:
var abc = new { id = 0, name = "david" };
It creates anonymous class object with one field called id. Look on msdn for details. Once you create object it cannot be extended.
This what this class looks like when open with .net Reflector
[CompilerGenerated, DebuggerDisplay(#"\{ id = {id} }", Type="<Anonymous Type>")]
internal sealed class <>f__AnonymousType0<<id>j__TPar>
{
// Fields
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly <id>j__TPar <id>i__Field;
// Methods
[DebuggerHidden]
public <>f__AnonymousType0(<id>j__TPar id);
[DebuggerHidden]
public override bool Equals(object value);
[DebuggerHidden]
public override int GetHashCode();
[DebuggerHidden]
public override string ToString();
// Properties
public <id>j__TPar id { get; }
}
So its compiled to regular class the basic difference is that it cannot be used outside of method scope.
I have a employee object as shown below
class emp
{
public int EmpID { get; set; }
public string EmpName { get; set; }
public int deptID { get; set; }
}
I need to create a mapping either in this class or a different class to map the properties with column name of my SQL
for eg. EmpdID="employeeID"
EmpName="EmployeeName"
deptID="DepartmentID"
When from my asp.net page when I create the employee class and pass it to a function:
for eg: emp e=new emp();
e.EmpID=1;
e.EmpName="tommy";
e.deptID=10;
When the emp object is populated and passed to the buildValues function it should return array of ComumnName(e.g.employeeID):Value(e.g.1),EmployeeName:tommy,DepartmentID:10)
string[] values=buildValues(emp);
public string[] buildValues(emp e)
{
string[] values=null;
return values;
}
I have 2 questions:
1. Where do I specify the mappings
2. How do I use the mappings in my buildValues function shown above and build the values string array.
I would really appreciate if you can help me with this
You need to use Reflection.
Specifically, you need to loop over typeof(Employee).GetProperties().
This is a solved problem. Do some research on ORM's and have a look at this SO question: .Net ORM that works well with MySQL
First of all, (as it was already said) it's best to leave this kind of mappings to an ORM tool, and just forget about them. However, ORM tools tend to be too "maternal" in protecting you from the gory details of data access and such, so it can be complicated to extend them, or change their behaviour.
That said, you could create a special class (Mappings) that would hold all mapping code. The mappings themselves are best kept in a dictionary, something like this:
static class Mappings
{
private static Dictionary<Type, Dictionary<string, string>> TypeMappings;
private static Dictionary<string, string> EmployeeMapping;
//... other mapped classes
static Mappings()
{
TypeMappings = new Dictionary<Type, Dictionary<string, string>>();
EmployeeMapping = new Dictionary<string, string>();
EmployeeMapping.Add("EmpID", "EmployeeID");
EmployeeMapping.Add("EmpName", "EmployeeName");
EmployeeMapping.Add("DeptID", "DepartmentID");
TypeMappings.Add(typeof(Employee),EmployeeMapping);
//... other mapped classes
}
public static string[] BuildValues<T>(T item)
{
if (!TypeMappings.ContainsKey(typeof(T)))
throw new Exception("wrong call");
Dictionary<string, string> mapping = TypeMappings[typeof(T)];
List<string> results = new List<string>();
foreach (var keyValuePair in mapping)
{
string propName = keyValuePair.Key;
string dbName = keyValuePair.Value;
PropertyInfo pi = typeof(T).GetProperty(propName);
object propValue = pi.GetValue(item, null);
results.Add(string.Format("{0}:{1}", dbName, propValue));
}
return results.ToArray();
}
}
Here, the TypeMappings is a dictionary of all mapped classes, whose mappings in turn are in propertyName - databaseName dictionaries.
The BuildValues method, takes those names, reflects the values, and build a results string.