This question already has answers here:
string to variable name
(4 answers)
Closed 9 years ago.
I am reading the name of a string variable from the database (e.g. "_datafile"). I want to know how I can access a named variable within my program using this string.
I have already tried using a dictionary, hash table, and a switch-case statement but I would like to have the variable resolve itself dynamically. Is this possible?
Do you mean you want to get the value of a field using the field name as a string?
public class MyClass
{
public string _datafile;
public MyClass()
{
_datafile = "Hello";
}
public void PrintField()
{
var result = this.GetType().GetField("_datafile").GetValue(this);
Console.WriteLine(result); // will print Hello
}
}
EDIT: #Rick, to respond to your comment:
public class MyClass
{
public IEnumerable<string> _parameters = new[] { "Val1", "Val2", "Val3" };
public void PrintField()
{
var parameters = this.GetType().GetField("_parameters").GetValue(this) as IEnumerable;
// Prints:
// Val1
// Val2
// Val3
foreach(var item in parameters)
{
Console.WriteLine(item);
}
}
}
If you want to get the value of a field based on its string name you will have to use reflection.
class MyClass
{
public int DataFile { get; set; }
public int _datafile;
}
var ob = new MyClass();
var typ = typeof(MyClass);
var f = typ.GetField("_datafile");
var prop = typ.GetProperty("DataFile");
var val = f.GetValue(ob);
var propVal = prop.GetValue(ob);
Usually you would create a class representing the values of one table record. If your table has an ID a FirstName and a LastName column, you would create a class like this
public class Person
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then you create a list of persons
var people = new List<Person>();
Now you can add persons to the list.
var p = new Person();
p.ID = 5;
p.FirstName = "John";
p.LastName = "Doe";
people.Add(p);
You can use a DataReader in order to read from a table
string sql = "SELECT * FROM tblPerson WHERE LastName LIKE #pattern";
cmd = new SqlCommand(sql);
cmd.Connection = "server=test;uid=sa;pwd=manager;database=northwind";
cmd.Parameters.AddWithValue("#pattern", "A%"); // Names beginning with "A"
using (SqlDataReader reader = cmd.ExecuteReader()) {
// Get column indexes
int idOrdinal = reader.GetOrdinal("ID");
int firstNameOrdinal = reader.GetOrdinal("FirstName");
int lastNameOrdinal = reader.GetOrdinal("LastName");
while(reader.Read()) {
var p = new Person();
p.ID = reader.GetInt32(idOrdinal);
p.FirstName = reader.GetString(firstNameOrdinal);
p.LastName = reader.GetString(lastNameOrdinal);
people.Add(p);
}
}
Related
I am developing micro-service with .NET Core.
The following code is working with an HttpPut request.
But if any field has empty or null value in our incoming JSON request, I want it to retrieve the previous value.
I don't want to constantly run the code below. Is there a short way around this?
if(updateCustomer.Surname != null && updateCustomer.Surname !=string.Empty)
{
customer.Surname = updateCustomer.Surname;
}
var serviceResponse = new ServiceResponse<GetCustomerDto>();
Customer customer = await _context.Customers.FirstOrDefaultAsync(c => c.Id == updateCustomer.Id);
var persons = (from p in _context.Customers where p.Id == updateCustomer.Id select p);
foreach (var person in persons)
{
person.Name = updateCustomer.Name;
person.Surname = updateCustomer.Surname;
person.BusinessCode = "123";
person.Phone = updateCustomer.Phone;
}
await _context.SaveChangesAsync();
serviceResponse.Data = _mapper.Map<GetCustomerDto>(customer);
Following the GetValueOrDefault() idiom from Nullable types, you can create a string extension method to select between two values like so:
public static class StringExtensions
{
public static string GetValueOrDefault(this string str, string alternative)
{
if(string.IsNullOrEmpty(str))
{
return alternative;
}
return str;
}
}
public class Program
{
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
public string BusinessCode { get; set; }
public string Phone { get; set; }
}
public static void Main()
{
Person previous = new Person
{
Name = null,
Surname = "Smith",
BusinessCode = "123",
Phone = "(555) 123-4567"
};
Person current = new Person
{
Name = "John",
Surname = string.Empty,
BusinessCode = "321",
Phone = "(555) 765-4321"
};
Person updated = new Person
{
Name = current.Name.GetValueOrDefault(previous.Name),
Surname = current.Surname.GetValueOrDefault(previous.Surname),
BusinessCode = current.BusinessCode.GetValueOrDefault(previous.BusinessCode),
Phone = current.Phone.GetValueOrDefault(previous.Phone)
};
}
}
I am working on dynamic query building in LINQ using Expression Tree.
I have taken the reference to the following post
https://www.codeproject.com/Tips/582450/Build-Where-Clause-Dynamically-in-Linq
How can I build expression if I want to check all the element in the list contains in another collection or not?
I have a Person class
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
and I have a list
List<Person> personList = new List<Person>()
{
new Person{ Name = "Shekhar", Age = 31},
new Person{ Name = "Sandip", Age = 32},
new Person{ Name = "Pramod", Age = 32},
new Person{ Name = "Kunal", Age = 33}
};
I have another list
List<string> nameList = new List<string>() { "Sandip", "Prashant" };
How can I build expression tree to check all the element in the list "nameList" contains in "personList" and give result true or false?
try this:
public bool Find(List<string> nameList, List<Person> personList)
{
foreach (var name in nameList)
if (personList.FirstOrDefault(person => person.Name == name) != null)
{
// Find
return true;
}
return false;
}
try this:
bool contained = !personList.Select(l=>l.Name).Except(nameList).Any();
I would like to make a query by using lambda select,
Like below:
public class Foo{
public int Id {get;set;}
public string Name {get;set;}
public string Surname {get;set;}
}
var list = new List<Foo>();
var temp = list.Select(x=> x("Name"),("Surname"));
The property name needs to be sent as a string,
I dont know how to use, I have given it for being a example.
is it possible?
Edit:
Foo list :
1 A B
2 C D
3 E F
4 G H
I don't know type of generic list, I have property name such as "Name", "Surname"
I want to be like below:
Result :
A B
C D
E F
G H
The following code snippet shows 2 cases. One filtering on the list, and another creating a new list of anonymous objects, having just Name and Surname.
List<Foo> list = new List<Foo>();
var newList = list.Select(x=> new {
AnyName1 = x.Name,
AnyName2 = x.Surname
});
var filteredList = list.Select(x => x.Name == "FilteredName" && x.Surname == "FilteredSurname");
var filteredListByLinq = from cust in list
where cust.Name == "Name" && cust.Surname == "Surname"
select cust;
var filteredByUsingReflection = list.Select(c => c.GetType().GetProperty("Name").GetValue(c, null));
Interface
If you have access to the types in question, and if you always want to access the same properties, the best option is to make the types implement the same interface:
public interface INamable
{
string Name { get; }
string Surname { get; }
}
public class Foo : INamable
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
}
This will preserve type safety and enable queries like this one:
public void ExtractUsingInterface<T>(IEnumerable<T> list) where T : INamable
{
var names = list.Select(o => new { Name = o.Name, Surname = o.Surname });
foreach (var n in names)
{
Console.WriteLine(n.Name + " " + n.Surname);
}
}
If, for some reason, you can't alter the original type, here are two more options.
Reflection
The first one is reflection. This is Mez's answer, i'll just rephrase it with an anonymous type like in the previous solution (not sure what you need exactly):
public void ExtractUsingReflection<T>(IEnumerable<T> list)
{
var names = list.Select(o => new
{
Name = GetStringValue(o, "Name"),
Surname = GetStringValue(o, "Surname")
});
foreach (var n in names)
{
Console.WriteLine(n.Name + " " + n.Surname);
}
}
private static string GetStringValue<T>(T obj, string propName)
{
return obj.GetType().GetProperty(propName).GetValue(obj, null) as string;
}
Dynamic
The second uses dynamic:
public void ExtractUsingDynamic(IEnumerable list)
{
var dynamicList = list.Cast<dynamic>();
var names = dynamicList.Select(d => new
{
Name = d.Name,
Surname = d.Surname
});
foreach (var n in names)
{
Console.WriteLine(n.Name + " " + n.Surname);
}
}
With that in place, the following code:
IEnumerable<INamable> list = new List<Foo>
{
new Foo() {Id = 1, Name = "FooName1", Surname = "FooSurname1"},
new Foo() {Id = 2, Name = "FooName2", Surname = "FooSurname2"}
};
ExtractUsingInterface(list);
// IEnumerable<object> list... will be fine for both solutions below
ExtractUsingReflection(list);
ExtractUsingDynamic(list);
will produce the expected output:
FooName1 FooSurname1
FooName2 FooSurname2
FooName1 FooSurname1
FooName2 FooSurname2
FooName1 FooSurname1
FooName2 FooSurname2
I'm sure you can fiddle with that and get to what you are trying to achieve.
var temp = list.Select(x => x.Name == "Name" && x.Surname == "Surname");
var temp = list.Select(x => new {Name = x.Name, Surname = x.Surname});
I have a situation, where I get data from the database in such a way, that everything is stored in one-dimensional array.
For example:
User table: UserId, Name
Group table: GroupId, Name
UserGroup table: UserId, GroupId
As a result of joining these tables I obtain array of the following form:
result[0] = "1" // user id
result[1] = "John Doe" // user name
result[2] = "121" // group id
result[3] = "SomeGroup" // group name
result[4] = "1" // user id
result[5] = "John Doe" // user name
result[6] = "2135" // group id
result[7] = "SomeOtherGroup" // group name
I know it's not a good solution of keeping data, but these data are coming to me from some other piece of code which I am not allowed to change, so I have to deal with it.
My questions are:
Is this possible to use LINQ in order to parse this array and place data in my own objects (User class with Groups collection in it).
What is other best way to handle it if not by LINQ?
Pure linq Expression :
int i = 0;
var objects = result.GroupBy(x => Math.Floor(i++ / 4.0))
.Select(g => new { id =g.ElementAt(0), name = g.ElementAt(1), gId= g.ElementAt(2), group = g.ElementAt(3)})
.GroupBy(x=>new {x.id, x.name}, x=>new {x.gId, x.group})
.Select(y=>new {y.Key, groups = y.ToList()});
In the first GroupBy I group results in 4 elements subsets using a floor and a temporary variable.
Then The next Select put the resulting arrays in an anonymous type for better usability in the next steps.
The next GroupBy is used to group the entries by Employee. The Key will be the employee and the values will be the corresponding Groups.
Finaly the lase Selectis used to put the GroupByresult in a better shape. I choose to put the result in an other anonymous type but You could instantiate you custom objects here and put the values in the right fields using curly brace constructor.
If your logic depends on indexes LINQ is is rarely the right tool. It results in less readable, maintainable, efficient and robust code than with plain loops.
I would use something like following to create two dictionaries representing the many to many relation. Note the for-loop which increments by 4 on every iteration since that seems to be the user-group-"package":
var userIdGroups = new Dictionary<int, HashSet<Group>>();
var groupIdUsers = new Dictionary<int, HashSet<User>>();
for(int i = 0; i < result.Length; i += 4)
{
int id;
if(int.TryParse(result[i], out id))
{
string name = result.ElementAtOrDefault(i + 1);
if(name == null)
continue; // end, invalid data
User user = new User{ UserId = id, Name = name };
string groupID = result.ElementAtOrDefault(i + 2);
if(!int.TryParse(groupID, out id))
continue; // end, invalid data
name = result.ElementAtOrDefault(i + 3);
if(name == null)
continue; // end, invalid data
Group group = new Group{ GroupId = id, Name = name };
HashSet<Group> userGroups;
HashSet<User> groupUsers;
if (userIdGroups.TryGetValue(user.UserId, out userGroups))
userGroups.Add(group);
else
userIdGroups.Add(user.UserId, new HashSet<Group>{ group });
if (groupIdUsers.TryGetValue(group.GroupId, out groupUsers))
groupUsers.Add(user);
else
groupIdUsers.Add(group.GroupId, new HashSet<User> { user });
}
}
The result is:
the user-dictionary contains one user with two groups
the group-dictionary contains two groups which map to the same user
You have to override Equals and GetHashCode to compare the ID's:
class User
{
public int UserId { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
User u2 = obj as User;
if (u2 == null) return false;
return UserId == u2.UserId;
}
public override int GetHashCode()
{
return UserId;
}
}
class Group
{
public int GroupId { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
Group g2 = obj as Group;
if (g2 == null) return false;
return GroupId == g2.GroupId;
}
public override int GetHashCode()
{
return GroupId;
}
}
You can do it with the basic structures like loops:
void Main()
{
var result = new string[] {"1","John Doe","2","Joes Group","3","Jack Daniel","4","Jacks Group","5","Foo Bar","6","FooBar Group",};
List<Person> personList = new List<Person>();
List<Group> groupList = new List<Group>();
for(int i = 0; i < result.Length; i+=2)
{
i = i + 2;
//check if group does not already exist
groupList.Add(new Group() {Name = result[i+1]});
}
for(int i = 0; i < result.Length; i+=2)
{
//check if person exists.
//if person only add group to person personList.Where(x => x.Name ==result[i+1])....
personList.Add(new Person() { Id = int.Parse(result[i]),
Name = result[i+1],
Groups = new List<Group>()
{
groupList.FirstOrDefault (l => l.Name == result[i+3])
}
});
i = i+2;
}
personList.Dump();
}
public class Person
{
public Person()
{
Groups = new List<Group>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Group> Groups { get; set; }
}
public class Group
{
public string Name { get; set; }
}
// Define other methods and classes here
Output:
Please take advise: this code does not contain any validation logic, or duplicate checks. You'll have to imlpement this by yourself.
But before you implement something like this, I'd rather change the way you get your data delivered. this way you would deal with the root of your peroblems not with the symptoms.
i think no need to linq
//some class
public class Result
{
public string UserId {get;set;}
public string UserName {get;set;}
public string GroupId {get;set;}
public string GroupName {get;set;}
public string UserGroupUserId {get;set;}
public string UserGroupUserName {get;set;}
public string UserGroupId {get;set;}
public string UserGroupGroupId {get;set;}
}
// your array
private void Form1_Load(object sender, EventArgs e)
{
string[] result = new string[8];
result[0] = "1";
result[1] = "John Doe";
result[2] = "121";
result[3] = "SomeGroup";
result[4] = "1";
result[5] = "John Doe";
result[6] = "2135";
result[7] = "SomeOtherGroup";
Result r = CastResult(result);
}
// simple cast array to some type
public Result CastResult(string[] array)
{
return new Result() { UserId=array[0], UserName=array[1], GroupId=array[2], GroupName=array[3], UserGroupUserId=array[4], UserGroupUserName=array[5] , UserGroupId=array[6], UserGroupGroupId=array[7] };
}
I am using c#
I have got below string in my variable.
string results = "Mr,Mike,Lewis,32,Project Manager,India";
Now I want to add these values in Dictionary type of session variable. I have declared a dict type variable in my code.
Dictionary<string, string> skywardsDetails = new Dictionary<string, string>();
Write now what I have written code was like below:
if (!string.IsNullOrEmpty(results))
{
string[] array = results.Split(',');
string title = array[0];
string firstname = array[1];
string lastname = array[2];
string age = array[3];
string designation = array[4];
string country = array[4];
//Here I want to write the new code which will add the results.Split(',') values in my Session variable as a Dictionary type.
foreach (string key in results.Split(','))
{
skywardsDetails.Add(key,//What to do here)
}
}
Please suggest
Your CSV results variable doesn't represent a dictionary. It represents an Employee model:
public class Employee
{
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string Designation { get; set; }
public string Country { get; set; }
}
and then:
var tokens = (results ?? string.Empty).Split(',');
if (tokens.Length > 5)
{
var employee = new Employee
{
Title = tokens[0],
FirstName = tokens[1],
LastName = tokens[2],
Age = int.Parse(tokens[3]),
Designation = tokens[4],
Country = tokens[5]
};
// TODO: do something with this employee like adding it
// to some dictionary, session, whatever
}
You cant really use foreach here and instead of declaring local variables replace that part with
skywardsDetails["title"] = array[0];
skywardsDetails["firstname"] = array[1];
skywardsDetails["lastname"] = array[2];
skywardsDetails["age"] = array[3];
skywardsDetails["designation"] = array[4];
skywardsDetails["country"] = array[5];
Now move those string constants to some constant like const string Title="title" and you will be able to get required field data from your dictionary like
string title= skywardsDetails[Constants.Title]
It would make more sense to use the dictionary like this:
skywardsDetails.Add("Title", array[0]);
skywardsDetails.Add("FirstName", array[1]);
// etc.
You shouldn't use the actual values as keys, as i think you want a generic way to access them.
Try something like this:
enum UserData
{
Title,
Firstname,
Lastname,
Age,
Designation,
Country
}
//========================================================
string results = "Mr,Mike,Lewis,32,Project Manager,India";
string[] array = results.Split(',');
var skywardsDetails = new Dictionary<UserData, string>();
// maybe you need some check data here
for (int i = 0; i < array.Length; i++)
{
skywardsDetails[(UserData)i] = array[i];
}