I see a lot of similar questions but none with a direct answer. I have a List<ClientEntry>. I want to access properties in ClientEntry. My code looks like this:
class ClientEntry
{
private string _clientName;
private string _clientEmail;
public void ClientEntry(string name, string email)
{
this._clientName = name;
this._clientEmail = email;
}
public string ClientName
{
get
{
return _clientName;
}
set
{
_clientName = value;
}
}
public string ClientEmail
{
get
{
return _clientEmail;
}
set
{
RegexUtilities Validator = new RegexUtilities();
if (Validator.IsValidEmail(value))
{
_clientEmail = value;
}
}
}
}
Later:
private List<ClientEntry> clientList;
I then add a bunch of ClientEntry's to the List.
How can I access the ClientName and ClientEmail properties for items in clientList? Also, how can I check for the existance of a certain ClientName or ClientEmail property within the List? Is this even possible with a list of objects? I know a dict would probably serve better, but I wanted to see if this could be done with a List and a class with properties.
You can use Linq to look for values inside of a list using Any()
Eg.
bool emailExists = clientList.Any(x=>x.ClientEmail == <email>);
To access values, you can use a index accessor if you know it, loop the collection, or use Where() to search it:
var email = clientList[index].ClientEmail
or
foreach (var client in clientList)
{
var email = client.ClientEmail
}
or
var email = clientList.Where(x=>x.ClientName == <clientName>).FirstOrDefault();
you can explore your list as below
foreach (ClientEntry client in clientList)
{
//client.ClientName
//client.ClientEmail
}
to find a particular record you can search it as
clientList.Where(p=> p.ClientEmail == "email#domain.com").FirstOrDefault();
To access a specific of item in the list, you input the index / using foreach
string name = clientList[index].ClientName;
foreach(var client in clientList)
{
name = client.ClientName; // access the item one by one
}
To check the existence of certain value of a property, use linq
bool isExist = clientList.Any(i => i.ClientName == "John");
Use Extension Methods !
Something like this, you can write unit test against the extension class easily and also it's straightforward to read.
public static class ClientEntriesExtension
{
public static bool ExistEmail(this IEnumerable<ClientEntry> entries, string targetEmail)
{
return entries.Any(x=>x.ClientEmail == targetEmail);
}
}
bool exist = clientList.ExistEmail(targetEmail)
Related
I am a little bit confused about how to read data from Excel. I am trying to import Excel for updating product list, I create an Excel model; I added all basic properties like name, price, quantity, etc. into this model. I will read all Excel and map into this model. That's ok, then I will give this model to EF Core 5 to save to SQL Server.
public class ExcelModel
{
public string Name { get; set }
public int Price { get; set }
public int Quantity { get; set }
}
I have a problem with product options. According to my DB schema, I have one table of products, one for options, one for option values, one for productOptionRelation.
Can you suggest another solution way or just solve on my way?
My colleges did this created field corresponding to values. like option1 and optionValue1, option2 and optionValue2 many of them, because each product could have many options. Model look like that, 20 option and 20 value was declared here and they manually map all these
For a temporary solution, I limited this option up to 5 and I created an list. and encapsulate all of them into list
public class ExcelOptionViewModel
{
public string Option { get; set; }
public string Value { get; set; }
}
This is my temp model, I encapsulated like that.
public IList<ExcelOptionViewModel> OptionModels { get; set; } = new List<ExcelOptionViewModel>();
public string Option1
{
get { return OptionModels[0].Option; }
set
{
this.OptionModels.Insert(0, new ExcelOptionViewModel { Option = value });
}
}
public string Option1Value
{
get { return OptionModels[0].Value; }
set { this.OptionModels[0].Value = value; }
}
This would be unlimited, You should enter how much you want
I have 2 solutions still I am researching one is, creating a method inside the excelviewmodel, this method will add all options and values into a list or I will use reflection, I am looking something like underlying type I will all option and values this underlying base type or something, when property loop came here, checking the type and assign all option1,option2,option3 or name like that properties to List<string> options, and same for the option values. I will use reading like option[0] and optionvalue[0]
Excel column names must be different because I read excel and turn it into datatable. Datatable column names must be different, it's not valid for reading into datatable
I used basically excel to data table function I can't remember but probably I found it in StackOverflow. Also, I added a feature there If some cell is null it will miss.
public List<T> ConvertDataTableToList<T>(DataTable dt)
{
//datatable clomun names
var columnNames = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName.ToLower()).ToList();
//selection properties equals to columnnames because I dont want loop for all props
var properties = typeof(T).GetProperties().Where(prp => columnNames.Any(t => t.ToLower() == prp.Name.ToLower()));
return dt.AsEnumerable().Select(row =>
{
var objT = Activator.CreateInstance<T>();
foreach (var pro in properties)
{
try
{
if (row[pro.Name] != DBNull.Value)
pro.SetValue(objT, row[pro.Name], null);
else
pro.SetValue(objT, null, null);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
return objT;
}).ToList();
}
I am looking something here when option1 or option2 comes here it would put this into a list
Also in my dt to model converter I dont want to use If but if some data value is null It throws an error which cant convert from dbnull value. If you have a suggest for it I would like release if condition :)
When All done I will map this excelviewmodel to product model something like this
foreach (var prop in SideParams.columns)
{
var source = row.GetType().GetProperty(prop);
var destination = product.GetType().GetProperty(prop);
if (destination != null && source.GetValue(row) != null)
{
Type t = Nullable.GetUnderlyingType(destination.PropertyType) ?? destination.PropertyType;
object safeValue = Convert.ChangeType(source.GetValue(row), t);
destination.SetValue(product, safeValue);
}
}
I saw something here
https://learn.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=net-6.0
it about binding flangs when reflecting model. "Specifies flags that control binding and the way in which the search for members and types is conducted by reflection." If there is way I can redirect option(1-2-3-4-5-6...) to list options
thanks for the help I solved my problem. If you need something like that, my solution is;
As you know OptionModels is what I created before, AddOptipns function is a new one I use for add data to list,
The function work with the ref, otherwise it must be static, if I turn it static, option models also must be static, so I can't access the list.
public IList<ExcelOptionViewModel> OptionModels { get; set; } = new List<ExcelOptionViewModel>();
public void AddOptions(ref String option, ref String value)
{
OptionModels.Add(new ExcelOptionViewModel { Option = option.Trim(), Value = value.Trim() });
}
And also add some new parts to convert model function,
calling that AddOptions method with reflection, I got an example from here
https://learn.microsoft.com/en-us/dotnet/api/system.reflection.bindingflags?view=net-6.0
I was inspired by the swap example there.
public List<T> ConvertDataTableToList<T>(DataTable dt)
{
var columnNames = dt.Columns.Cast<DataColumn>().Select(c => c.ColumnName.ToLower()).ToList();
//selection properties equals to columnnames because I dont want loop for all props
var type = typeof(T);
var properties = type.GetProperties().Where(prp => columnNames.Any(t => t.ToLower() == prp.Name.ToLower())).ToList();
var productOptions = columnNames.Where(x => x.Contains("option")).ToList() ?? new List<string>();
return dt.AsEnumerable().Select(row =>
{
var objT = Activator.CreateInstance<T>();
foreach (var pro in properties)
{
try
{
if (row[pro.Name] != DBNull.Value)
pro.SetValue(objT, row[pro.Name], null);
else
pro.SetValue(objT, null, null);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
for (var i = 0; i < productOptions.Count(); i += 2)
{
object[] argValues = new object[] { row[productOptions[i]].ToString(), row[productOptions[i + 1]].ToString() };
String[] argNames = new String[] { "option", "value" } ;
var method = type.GetMethod("AddOptions");
method.Invoke(objT, argValues);
}
return objT;
}).ToList();
}
here is the added data :)
This is best I could make the question statement. Please be kind.
Here is the situation:
I have a string "InputValues" which contains values in comma seperated format:
chkAwareness1,chkAwareness2,chkAwareness6,chkAwareness9,chkAwareness13...
I need to fill an object with bool value if the name matches with what I have in above string variable.
example:
if InputValues contains "chkAwareness1" then "public bool chkAwareness1" should set to true, otherwise false.
public class SurveyCheckBox
{
public bool chkAwareness1 { get; set; }
public bool chkAwareness2 { get; set; }
public bool chkAwareness3 { get; set; }
public bool chkAwareness4 { get; set; }
public bool chkAwareness5 { get; set; }
public bool chkAwareness6 { get; set; }
public bool chkAwareness7 { get; set; }
.
.
.
}
public void createObjectSurveyCheckBox(string InputValues)
{
string[] ChkValues = InputValues.Split(',');
SurveyCheckBox surveyChkBoxObj = new SurveyCheckBox();
for (int i = 0; i < NumberOfPropertyInSurveyCheckBox ;i++ )
{
// typeof(SurveyCheckBox).GetProperties()[i].Name
}
}
I searched and I found GetProperties method through which I can get the name of property, but I am unable to figure out the logic.. how to search through the values and assign them to bool properties.
Please help.
You're very close. You just need to change your loop, really. The whole method should look like this:
public void CreateObjectSurveyCheckBox(string inputValues)
{
string[] chkValues = inputValues.Split(',');
SurveyCheckBox surveyChkBoxObj = new SurveyCheckBox();
foreach (string value in chkValues)
{
PropertyInfo propInfo = typeof(SurveyCheckBox).GetProperty(value);
if (propInfo != null)
propInfo.SetValue(surveyChkBoxObj, true);
}
}
P.S. You'll notice I took the liberty of changing your capitalization to something much more standard. If you use capitalization like you had, you're likely to get lynched.
I agree with Tim; I would not use something like this in production code.
public void createObjectSurveyCheckBox(string InputValues)
{
var instance = new SurveyCheckBox();
foreach (var property in typeof(SurveyCheckBox).GetProperties().Where(x => x.Name.Contains("chkAwareness")))
{
if (InputValues.Contains(property.Name))
property.SetValue(instance, true);
}
}
I would write the loop from the other direction, from 0 to MaxchkAwareness;
Sort the input first, before going into the loop.
You would also need an index to the next item in your input array (ChkValues), lets call that chkValueIndex;
If the next item in your input array, ChkValues[chkValueIndex], is "chkAwareness"+i.ToString()
then your property is true, and you increment your array pointer .
otherwise your property is false.
But I think you have to use reflection to set the properties in a loop like that, something like this:
Getting a property reference using reflection
I am sure there are better ways to restructure this and do it entirely different, but it sounds to me like you are trying to do the best you can with the system that was given you.
You can try this:
public static void createObjectSurveyCheckBox(string InputValues)
{
string[] ChkValues = InputValues.Split(',');
SurveyCheckBox surveyChkBoxObj = new SurveyCheckBox();
foreach (var prop in typeof(SurveyCheckBox).GetProperties())
{
if (ChkValues.Contains(prop.Name))
prop.SetValue(surveyChkBoxObj, true);
}
}
I am creating an application in C# using a ListView control that lets you create lists. I am implementing a Find function using the Find() method. Here’s my code:
if (findTextBox.Text != "")
{
ListViewItem[] lviFoundList = listItemsList.Items.Find(findTextBox.Text, true);
amountFound.Text = "Found " + Convert.ToString(lviFoundList.Count());
if (lviFoundList.Count() != 0)
{
int firstItemIndex = lviFoundList[0].Index;
listItemsList.Items[firstItemIndex].Selected = true;
}
}
else
{
amountFound.Text = "Found 0";
}
However, it doesn’t return any matches. What am I doing wrong?
Find method requires your listView item's Name, did you set your list view item's name property? If you want to search for text you can use this:
var lviFoundList = new List<ListViewItem>();
foreach(var item in listItemsList.Items)
{
if(item.Text == findTextBox.Text) lviFoundList.Add(item);
}
The Find() Method looks at the ListViewItem's name, not it's text.
You want this instead:
if (findTextBox.Text != "")
{
List<ListViewItem> items = new List<ListViewItems>();
foreach ListViewItem lvi in listItemsList.Items
{
if (lvi.Text == findTextBox.Text)
items.Add(lvi);
}
amountFound.Text = "Found " + Convert.ToString(lviFoundList.Count());
if(lviFoundList.Count() != 0)
{
int firstItemIndex = lviFoundList[0].Index;
listItemsList.Items[firstItemIndex].Selected = true;
}
}
else
{
amountFound.Text = "Found 0";
}
Honestly, the ListView.Find() method is rather poor and it's much easier to roll your own with LINQ. Think about what Find really is trying to accomplish -- a specific filtering, typically one record.
The first step, if you haven't already, would be to keep a cached collection of your data objects. Let's assume you have a list of Person classes like so:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string JobTitle { get; set; }
public DateTime DateOfBirth { get; set; }
}
Then in your MainForm you have a ListView and a member variable people defined as a List<Person>. Your ListView.Items should reflect the contents of this List<Person>.
So now maybe you want to find a person based on their FirstName or LastName, right? You could use LINQ in a function like so:
int FindFirstIndexOfPersonNamed(string firstOrLastName)
{
// WARNING: This is case sensitive!
return people.FindIndex(p => p.FirstName.Contains(firstOrLastName) || p.LastName.Contains(firstOrLastName));
}
Since your ListView.Items should be reflecting your List<Person> the index should be identical:
// Get the found item and do whatever you want with it...
var selectedListViewItem = listView.Items[index];
I am not sure what the best and simplest way to do this, so any advice is appreciated.
I want to get all the fields on any/all/single domain entity class and add prefix/remove prefix dynamically when calling a particular method.
For example, I have entities such as:
public class Shop
{
public string TypeOfShop{get;set}
public string OwnerName {get;set}
public string Address {get;set}
}
public class Garage
{
public string Company {get;set}
public string Name {get;set}
public string Address {get;set}
}
and so on...
I want to get a list of the properties with a prefix:
public Class Simple
{
public class Prop
{
public string Name{get;set;}
public string Value{get;set;}
}
public ICollection list = new List<Prop>();
//set all prop
public void GetPropertiesWithPrefix(Garage mygarage, string prefix)
{
list.Add(new Prop{Name = prefix + "_Company", Value = mygarage.Company});
//so on... upto 50 props...
}
}
//to get this list I can simple call the list property on the Simple class
When reading each field I am using a switch statement and setting the value.
//Note I return a collection of Prop that have new values set within the view,lets say
//this is a result returned from a controller with the existing prop names and new values...
public MyGarage SetValuesForGarage(MyGarage mygarage, string prefix, ICollection<Prop> _props)
{
foreach (var item in _prop)
{
switch(item.Name)
{
case prefix + "Company":
mygarage.Company = item.Value;
break;
//so on for each property...
}
}
}
Is there a better, simpler or more elegant way to do this with linq or otherwise?
You could store props in a dictionary, then have:
mygarage.Company = _props[prefix + "_Company"];
mygarage.Address = _props[prefix + "_Address"];
//And so on...
in your SetValuesForGarage method instead of a loop with a switch inside.
EDIT
For more info on using Dictionary see MSDN.
You can define list something like:
Dictionary<string, string> list = new Dictionary<string, string>();
And have something like the following in your GetPropertiesWithPrefix method:
list.Add(prefix + "_Company", mygarage.Company);
list.Add(prefix + "_Address", mygarage.Address);
//And so on...
This would eliminate your Prop class.
Maybe the following method works for you. It takes any object, looks up its properties and returns a list with your Prop objects, each for every property.
public class PropertyReader
{
public static List<Prop> GetPropertiesWithPrefix(object obj, string prefix)
{
if (obj == null)
{
return new List<Prop>();
}
var allProps = from propInfo
in obj.GetType().GetProperties()
select new Prop()
{
Name = prefix + propInfo.Name,
Value = propInfo.GetValue(obj, null) as string
};
return allProps.ToList();
}
}
I am abit new in C# and i am trying to insert an object to a CheckedListBox,
so this inserted item will have a title inside the checked list (my object contains a string field inside it which I want to be displayed in the CheckedListBox).
for example this is my class:
public class InfoLayer
{
private string LayerName;
private List<GeoInfo> GeoInfos;
public InfoLayer()
{
LayerName = "New Empty Layer";
GeoInfos = new List<GeoInfo>();
}
public InfoLayer(string LayerName)
{
this.LayerName = LayerName;
GeoInfos = new List<GeoInfo>();
}
public InfoLayer(string LayerName,List<GeoInfo> GeoInfosToClone):this(LayerName)
{
foreach (GeoInfo item in GeoInfosToClone)
{
GeoInfos.Add((GeoInfo)((ICloneable)item).Clone());
}
}
public GeoInfo SearchElement(long id)
{
foreach (GeoInfo info in GeoInfos) // foreach loop running on the list
{
if (info.INFOID == id)
return info; // return the item if we found it
}
return null;
}
public GeoInfo SearchElement(string name)
{
foreach (GeoInfo info in GeoInfos)
{
if (info.INFONAME.CompareTo(name)==0)
return info;
}
return null;
}
public override string ToString()
{
string toReturn = "";
for (int i = 0; i < GeoInfos.Count; i++) // for loop running on the list
{
toReturn += String.Format("{0}\n",GeoInfos[i].ToString()); // piping another geoinfo
}
return toReturn;
}
public string LAYERNAME{get{return LayerName;}}
my class also contains a tostring overrider inside her (not what i want to display)
thanks in advance for your help.
Override ToString() in your class, the class that the object is an instance of.
Edit:
You don't want to display the contents of ToString(). You want to display the LayerName, don't you? Perhaps you should display the values with Databinding instead. Then you can set DisplayMember to your new LAYERNAME property.
I believe this is what you are trying to achieve:
checkedListBox1.Items.Add(yourObject.stringField);
((MyObjectType)checkedListBox1.Items(index)).Name = "whatever"
You will have to know the index of the object you want to change.
You'll just have to override the ToString method in your class so that it returns this Name property value.
public overrides string ToString() {
return Name;
}
It will then display its name when added to your CheckedListbox.