I'm sure I remember this being a threading issue, but I can't find an answer. It seems like it should be simple. I have the following code:
private void Dingle_Clicked(object sender, RoutedEventArgs e)
{
dynamic doc = ScraperBrowser.Document;
string htmlText = doc.documentElement.InnerHtml;
htmlText = htmlText.Replace("\r\n", " ");
Regex targetStart = new Regex(this works just fine);
MatchCollection target = targetStart.Matches(htmlText);
string priceData = target[0].Value;
foreach (StorePriceData spData in Lists.Singleton.MedicineList[medIndex].Prices)
{
Regex rx = new Regex(spData.StoreName + #".+?(\$\d+\.\d+)");
MatchCollection matches = rx.Matches(priceData);
if (matches.Count > 0)
{
if (matches[0].Groups.Count > 0)
{
spData.MedicinePrice = matches[0].Groups[1].Value;
}
}
}
string cookie = Application.GetCookie(new Uri("https://www.goodrx.com"));
++medIndex;
ScraperBrowser.Navigate(Lists.Singleton.MedicineList[medIndex].GoodRxUrlString);
}
The problem I'm having is that the spData.MedicinePrice takes the value, but the value in the singleton "MedicineList" is not being updated. How can I make that value update?
The singleton code:
public class Lists
{
private static Lists _singleton;
public static Lists Singleton
{
get
{
if (_singleton == null) _singleton = new Lists(); return _singleton;
}
}
public List<MedicineInfo> MedicineList {
get
{
return new List<MedicineInfo>()
{
new MedicineInfo() { Name = "ZOLPIDEM TAB 10MG", Doses = "30 tablets" },
new MedicineInfo() { Name = "PANTOPRAZOLE TAB 40MG", Doses = "30 tablets" }
};
}
}
}
MedicineInfo class code:
public class MedicineInfo
{
public MedicineInfo()
{
Prices = new List<StorePriceData>()
{
new StorePriceData() { StoreName = "xxxx" },
new StorePriceData() { StoreName = "yyyy" },
new StorePriceData() { StoreName = "zzzz" },
};
}
public string Name { get; set; }
public string Doses { get; set; }
public List<StorePriceData> Prices { get; set; }
}
Thanks!
Carl
You are returning a new List<MedicineInfo> each time the getter of MedicineList is called.
Also, Lists is not really a singleton. A better implementation would look something like this:
public sealed class Lists
{
private static readonly Lists _singleton = new Lists();
private readonly List<MedicineInfo> _medicineList = new List<MedicineInfo>
{
new MedicineInfo() { Name = "ZOLPIDEM TAB 10MG", Doses = "30 tablets" },
new MedicineInfo() { Name = "PANTOPRAZOLE TAB 40MG", Doses = "30 tablets" }
};
private Lists() { }
public static Lists Singleton => _singleton;
public List<MedicineInfo> MedicineList => _medicineList;
}
Related
I would like to make a method to print a LINQ (table) with all its properties and values to the console.
I'm currently trying to do this via the System.Reflection.GetType().GetProperties()
What I think is going wrong is the type of parameter I try to send to the method. If possible this should be a var so I can use this method with any class list. (not sure if this is possible)
The issue is with the printtabel() method.
I started from:
Print a table with LINQ
namespace LINQ
{
class Program
{
public class Bier
{
public int BierNr { get; set; }
public string Biernaam { get; set; }
public float Alcohol { get; set; }
public Brouwer Brouwer { get; set; } //associatie met een brouwer
public override string ToString() { return Biernaam + ": " + Alcohol + "% alcohol"; }
}
public class Brouwer
{
public int BrouwerNr { get; set; }
public string Brouwernaam { get; set; }
public bool Belgisch { get; set; }
public List<Bier> Bieren { get; set; }
public override string ToString() { return "Brouwerij " + Brouwernaam + " (" + (Belgisch ? "Belgisch" : "Niet Belgisch") + ")"; }
}
public class Brouwers
{
public List<Brouwer> GetBrouwers()
{
List<Brouwer> lijst = new List<Brouwer>();
Brouwer palm = new Brouwer { BrouwerNr = 1, Brouwernaam = "Palm", Belgisch = true };
palm.Bieren = new List<Bier> {
new Bier {BierNr=1,Biernaam="Palm Dobbel", Alcohol=6.2F, Brouwer=palm},
new Bier {BierNr=2, Biernaam="Palm Green", Alcohol=0.1F, Brouwer=palm},
new Bier {BierNr=3, Biernaam="Palm Royale", Alcohol=7.5F, Brouwer=palm}
};
lijst.Add(palm);
Brouwer hertogJan = new Brouwer { BrouwerNr = 2, Brouwernaam = "Hertog Jan", Belgisch = false };
hertogJan.Bieren = new List<Bier> {
new Bier{ BierNr=4, Biernaam="Hertog Jan Dubbel", Alcohol=7.0F, Brouwer=hertogJan},
new Bier{ BierNr=5, Biernaam="Hertog Jan Grand Prestige", Alcohol=10.0F, Brouwer=hertogJan} };
lijst.Add(hertogJan);
Brouwer inBev = new Brouwer { BrouwerNr = 3, Brouwernaam = "InBev", Belgisch = true };
inBev.Bieren = new List<Bier> {
new Bier { BierNr=6, Biernaam="Belle-vue kriek L.A", Alcohol=1.2F, Brouwer=inBev},
new Bier { BierNr=7, Biernaam="Belle-vue kriek", Alcohol=5.2F, Brouwer=inBev},
new Bier { BierNr=8, Biernaam="Leffe Radieuse", Alcohol=8.2F,Brouwer=inBev},
new Bier { BierNr=9, Biernaam="Leffe Triple", Alcohol=8.5F,Brouwer=inBev} };
lijst.Add(inBev);
//return new List<Brouwer> { palm, hertogJan, inBev };
return lijst;
}
}
static void Main(string[] args)
{
var brouwers = new Brouwers().GetBrouwers();
var belgischeBrouwerijenMet3Bieren =
from brouwer in brouwers
where brouwer.Belgisch && brouwer.Bieren.Count == 3
select brouwer;
foreach (var brouwer in belgischeBrouwerijenMet3Bieren)
Console.WriteLine(brouwer.Brouwernaam);
var bieren = from brouwer in brouwers
from bier in brouwer.Bieren
select bier;
string vorigeBrouwer = "";
foreach (var bier in bieren)
{
if (bier.Brouwer.ToString() != vorigeBrouwer)
{
Console.WriteLine(bier.Brouwer);
vorigeBrouwer = bier.Brouwer.ToString();
}
Console.WriteLine($"\t {bier.ToString()}");
}
Console.WriteLine(printtabel(belgischeBrouwerijenMet3Bieren));
Console.ReadLine();
}
public string printtabel(IEnumerable<Brouwer> response)
{
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo prop in response.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
object value = prop.GetValue(response, new object[] { });
sb.AppendLine($"{prop.Name} = {value}");
}
return sb.ToString();
}
}
}
Error CS0120 An object reference is required for the non-static field, method, or property 'Program.printtabel(IEnumerable)' LINQ 204 Active
You can fix it by writing:
public static string printtabel(IEnumerable<Brouwer> response)
You are calling a non static method from a static method. Set printtabel static and this error should disappear.
Want to assign CustomEditor to PropertyGridControl. If I try using default way it does not work, however I am trying alternative which is not suitable for my case.
Class and Custom editor which is needs to be assigned to PropertyGridControl:
public class Foo
{
public Foo()
{
}
public Language LanguageOfFoo { get; set; }
}
public class Language
{
public Language()
{
}
public int ID { get; set; }
public string Name { get; set; }
}
public class RepositoryItemForLanguage : RepositoryItemLookUpEdit
{
public RepositoryItemForLanguage()
{
this.Columns.AddRange(new DevExpress.XtraEditors.Controls.LookUpColumnInfo[] {
new DevExpress.XtraEditors.Controls.LookUpColumnInfo("Name", "Name")}
);
this.DisplayMember = "Name";
List<Language> tmpList = new List<Language>();
tmpList.Add(new Language { ID = 1, Name = "AZE" });
tmpList.Add(new Language { ID = 2, Name = "ENG" });
tmpList.Add(new Language { ID = 1, Name = "RUS" });
this.DataSource = tmpList;
}
}
Default way:
private void button1_Click(object sender, EventArgs e)
{
propertyGridControl1.Rows.Clear();
propertyGridControl1.DefaultEditors.Clear();
propertyGridControl1.RepositoryItems.Clear();
propertyGridControl1.SelectedObject = null;
Foo f1 = new Foo();
f1.LanguageOfFoo = new Language();
RepositoryItemForLanguage repItem = new RepositoryItemForLanguage();
propertyGridControl1.RepositoryItems.Add(repItem);
propertyGridControl1.DefaultEditors.Add(typeof(Language), repItem);
propertyGridControl1.DefaultEditors.AddRange(new DevExpress.XtraVerticalGrid.Rows.DefaultEditor[] {
new DevExpress.XtraVerticalGrid.Rows.DefaultEditor(typeof(Language), repItem)});
propertyGridControl1.RepositoryItems.AddRange(new RepositoryItem[] { repItem});
propertyGridControl1.SelectedObject = f1;
}
Alternative method:
private void button1_Click(object sender, EventArgs e)
{
propertyGridControl1.Rows.Clear();
propertyGridControl1.DefaultEditors.Clear();
propertyGridControl1.RepositoryItems.Clear();
propertyGridControl1.SelectedObject = null;
Foo f1 = new Foo();
f1.LanguageOfFoo = new Language();
RepositoryItemForLanguage repItem = new RepositoryItemForLanguage();
propertyGridControl1.RepositoryItems.Add(repItem);
propertyGridControl1.SelectedObject = f1;
propertyGridControl1.GetRowByFieldName("LanguageOfFoo").Properties.RowEdit = repItem;
}
As you see it is possible only with "GetRowByFieldName" methods and specifying exact property name.
Appreciate for your help.
I have an interesting question, one I'm having difficulty searching for an answer on.
I have two IEnumerable collections of objects. The underlying objects are completely separate, BUT I can identify a shared key that should match. The collections are important, in that my "left" object is the "system of record", and the "right" object is representing a system I need to ensure matches the system of record.
Once they are matched, I need to perform CRUD operations on one side to bring the right side in line with the left side. For example, it would create a new item on the right side if one didn't exist, or update values, or delete if the item was missing on the left, but not the right.
The catch is, I have hundreds of these collections to match up, and the actual CRUD code is different.
I'd like to introduce some shared code where I can pass in both collections, the collection types (as probably generics), some kind of comparer, and some delegates of what operation to perform for CRUD.
If this code actually existed, it may look something like this
class Stuff
{
string Id {get; set;}
string Name {get; set;}
}
class Junk
{
string Id {get; set;}
string ShortName {get; set;}
}
IEnumerable<Stuff> myStuff = GetStuff();
IEnumerable<Junk> myJunk = GetJunk();
CrudComparer cc = new CrudComparer<Stuff, Junk>(myStuff, myJunk);
cc.Comparer = (leftObject, rightObject) => {
leftObject.Name == rightObject.Name
}
cc.CreateOperation = (newObject, rightCollection) => {
Junk j = new Junk();
j.Shortname = newObject.Name;
rightCollection.Add(j);
}
cc.UpdateOperation = (leftObject, rightObject) => {
rightObject.Shortname = leftObject.Name;
}
cc.DeleteOperation = (rightCollection, rightObject) => {
rightCollection.Remove(rightObject);
}
cc.Compare();
Has anyone ever seen code that does something like this? I'd hate to reinvent the wheel if I can grab something already done.
Thanks for any help!
--Michael
I got to thinking more about this, and realized what I knew about delgates and generics should be sufficient to solve this problem, so I got in LinqPad and had some fun. I haven't written any unit tests around this yet, so use at your own risk, but hopefully if you want to use this you understand the underlying concepts.
class Blah
{
public int ID { get; set; }
public string BlahName { get; set;}
}
class Bleh
{
public int ID { get; set; }
public string BlehName { get; set;}
}
class CrudComparer<TLeft, TRight>
{
private readonly ICollection<TLeft> _leftCollection;
private readonly ICollection<TRight> _rightCollection;
private readonly Comparer _compareOperation;
private readonly CreateOperation _createOperation;
private readonly UpdateOperation _updateOperation;
private readonly DeleteOperation _deleteOperation;
public delegate bool Comparer(TLeft leftItem, TRight rightItem);
public delegate void CreateOperation(TLeft leftItem, ICollection<TRight> rightCollection);
public delegate void UpdateOperation(TLeft leftItem, TRight rightItem);
public delegate void DeleteOperation(TRight rightItem, ICollection<TRight> rightCollection);
public CrudComparer(ICollection<TLeft> leftCollection, ICollection<TRight> rightCollection, Comparer compareOperation, CreateOperation createOperation, UpdateOperation updateOperation, DeleteOperation deleteOperation)
{
_leftCollection = leftCollection;
_rightCollection = rightCollection;
_compareOperation = compareOperation;
_createOperation = createOperation;
_updateOperation = updateOperation;
_deleteOperation = deleteOperation;
}
public void Compare()
{
foreach (TLeft leftItem in _leftCollection)
{
bool foundItem = false;
foreach (TRight rightItem in _rightCollection)
{
if (_compareOperation(leftItem, rightItem))
{
//these equal
foundItem = true;
}
}
if (foundItem == false)
{
_createOperation(leftItem, _rightCollection);
}
}
List<TRight> itemsToDelete = new List<TRight>();
foreach (TRight rightItem in _rightCollection)
{
bool foundItem = false;
foreach (TLeft leftItem in _leftCollection)
{
if (_compareOperation(leftItem, rightItem))
{
foundItem = true;
_updateOperation(leftItem, rightItem);
break;
}
}
if (!foundItem)
{
itemsToDelete.Add(rightItem);
}
}
foreach (TRight itemToDelete in itemsToDelete)
{
_deleteOperation(itemToDelete, _rightCollection);
}
}
}
void Main()
{
List<Blah> blahItems = new List<Blah>();
blahItems.Add(new Blah() { ID = 1, BlahName = "Blah" });
blahItems.Add(new Blah() { ID = 2, BlahName = "ABC" });
blahItems.Add(new Blah() { ID = 34, BlahName = "XYZ" });
blahItems.Add(new Blah() { ID = 6442, BlahName = "123" });
List<Bleh> blehItems = new List<Bleh>();
blehItems.Add(new Bleh() { ID = 2, BlehName = "12345"});
blehItems.Add(new Bleh() { ID = 6, BlehName = "43232"});
blehItems.Add(new Bleh() { ID = 77, BlehName = "BlahBlah"});
blehItems.Add(new Bleh() { ID = 2334, BlehName = "ZYX"});
CrudComparer<Blah, Bleh>.Comparer compareOperation = (leftObject, rightObject) =>
{
return leftObject.ID == rightObject.ID;
};
CrudComparer<Blah, Bleh>.CreateOperation createOperation = (leftObject, rightCollection) =>
{
rightCollection.Add(new Bleh() { ID = leftObject.ID });
};
CrudComparer<Blah, Bleh>.UpdateOperation updateOperation = (leftObject, rightObject) =>
{
rightObject.BlehName = leftObject.BlahName;
};
CrudComparer<Blah, Bleh>.DeleteOperation deleteOperation = (rightObject, rightCollection) =>
{
rightCollection.Remove(rightObject);
};
CrudComparer<Blah, Bleh> cc = new CrudComparer<Blah, Bleh>(blahItems, blehItems, compareOperation, createOperation, updateOperation, deleteOperation);
cc.Compare();
}
I want to create 3 methods, 2 to declare and initialize arrays. And 3rd to loop through the 2 arrays. I want to invoke the third method in main() to display each index of array2 grouped under array1 index. I hope I have put my question through clearly.
class Program
{
static void Main(string[] args)
{
Program p = new Program();
p.display(Carnivore, ZooMammals);
}
public void Mammals(ZooMammals[] category)
{
category = new ZooMammals[4];
category[1] = new ZooMammals() {Category="Carnivorous", Attribute = new Attributes[2] };
category[2] = new ZooMammals() { Category = "Carnivorous", Attribute= new Attributes[1] };
category[3] = new ZooMammals() { Category = "Carnivorous", Attribute = new Attributes[3] };
}
public static void Carnivore(Attributes[] Carn)
{
Carn = new Attributes[3];
Carn[0] = new Attributes() { Sex ="M", colour = "yellow",Name="Lion" };
Carn[1] = new Attributes() { Sex ="F", colour = "yellow",Name="Cat"};
Carn[2] = new Attributes() { Sex ="M", colour = "yellow",Name="Tiger"};
}
public static void display(Attributes[] Carn,ZooMammals[] category)
{
foreach (var a in category)
{
if (a == null) continue;
Console.WriteLine("{0},{1},{2}", a.Category, a.Attribute);
}
foreach (var x in category.Carn)
{
if (x == null) continue;
Console.WriteLine("{0},{1},{2}", x.Sex, a.colour, x.Name);
Console.WriteLine(category[1].Carn[0]);
Console.WriteLine(category[1].Carn[1]);
Console.WriteLine(category[1].Carn[2]);
Console.WriteLine(category[2].Carn[0]);
Console.WriteLine(category[2].Carn[1]);
}
Console.ReadLine();
}
}
public class Attributes
{
public string Sex;
public string colour;
public string Name;
}
public class ZooMammals
{
public string Category;
public Attributes[] Attribute;
}
}
static void Main(string[] args)
{
Program p = new Program();
p.display(Mammals(), Carnivore());
}
public ZooMammals[] Mammals()
{
ZooMammals[] category = new ZooMammals[4];
category[1] = new ZooMammals() {Category="Carnivorous", Attribute = new Attributes[2] };
category[2] = new ZooMammals() { Category = "Carnivorous", Attribute= new Attributes[1] };
category[3] = new ZooMammals() { Category = "Carnivorous", Attribute = new Attributes[3] };
return category;
}
public Attributes[] Carnivore()
{
Attributes[] Carn = new Attributes[3];
Carn[0] = new Attributes() { Sex ="M", colour = "yellow",Name="Lion" };
Carn[1] = new Attributes() { Sex ="F", colour = "yellow",Name="Cat"};
Carn[2] = new Attributes() { Sex ="M", colour = "yellow",Name="Tiger"};
return Carn;
}
This is where you are going wrong i feel. This can be done better by declaring two global arrays and just assigning values in the methods and using the same through out the code.
I just cannot get this to work, would appreciate if someone can help.
So I get back an XML result from a database which looks like:
<matches>
<issuer client_name="MTR" score="6" match_list="MTR CORPORATION LIMITED"/>
<issuer client_name="PEOPLE''S REPUBLIC OF CHINA" score="4"
match_list="DEMOCRATIC PEOPLE'S REPUBLIC OF KOREA;GOVERNMENT OF THE
HONG KONG SPECIAL ADMINISTRATIVE REGION OF THE PEOPLE'S REPUBLIC OF
CHINA;MONGOLIAN PEOPLE'S REPUBLIC;PEOPLE'S DEMOCRATIC REPUBLIC OF
ALGERIA;PEOPLE'S REPUBLIC OF CHINA"/>
</matches>
From this XML I need to populate an object after doing some logic like matching the client_name I am getting back in the XML result to the one I have sent to database to get matches.
XDocument.Load(new StringReader(
row.GetString(row.GetOrdinal("xml_ret"))))))
.Single().Descendants("matches")
.Select(x =>
new Pool() {
Constituents = (IEnumerable<Constituent>)
//(... cannot work this how can IsReference populate)
//ClientName = x.Attribute("client_name").Value,
//Score = x.Attribute("score").Value,
//MatchList = x.Attribute("match_list").Value,
});
In a non-LINQ manner I can populate the object something like this:
foreach (Constituent constituent in pool.Constituents)
{
if (!string.IsNullOrEmpty(constituent.Name)
&& string.IsNullOrEmpty(constituent.Curve))
{
i++;
ConstituentMatch match = new ConstituentMatch();
ConstituentMatch.Group group =new ConstituentMatch.Group("High");
//High Match group
ICollection<string> curves = new List<string>();
curves.Add("EUR" + i);
curves.Add("USD" + i);
ICollection<string> names = new List<string>();
ConstituentMatch.Group.Entry entry =
new ConstituentMatch.Group.Entry(constituent.Name + " Ltd.",
curves);
group.Add(entry);
entry =
new ConstituentMatch.Group.Entry(constituent.Name + " Inc.",
curves);
group.Add(entry);
match.AddGroup(group);
}
}
But how can I do this using LINQ, as I am sure you can do it, I just cannot work it out.
The constituent class looks like:
public sealed class Constituent
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public ConstituentMatch Match {get;set;}
public Constituent(string name)
{
this.name = name;
}
public Constituent() : this(string.Empty) { }
}
And constituent match class looks like this:
public sealed class ConstituentMatch
{
private readonly Dictionary<string, Group> matches = new Dictionary<string, Group>();
public IEnumerable<string> GroupNames
{
get { return matches.Keys; }
}
public Group this[string name]
{
get { return matches[name]; }
}
public IEnumerable<Group> Groups
{
get { return matches.Values; }
}
public void AddGroup(Group group)
{
matches[group.Name] = group;
}
/// <summary>
/// Match group e.g. Poor, High, All, Begins With
/// </summary>
public sealed class Group
{
private readonly string name;
private readonly ICollection<Entry> matches = new List<Entry>();
public string Name
{
get { return name; }
}
public Group(string name)
{
this.name = name;
}
public void Add(Entry entry)
{
matches.Add(entry);
}
public override bool Equals(object obj)
{
bool result = false;
if (obj is Group)
{
Group other = obj as Group;
result = name == other.name;
}
return result;
}
public override int GetHashCode()
{
return name.GetHashCode();
}
public sealed class Entry
{
private string legalName;
private IEnumerable<string> curves;
private double notional = double.NaN;
private char seniriority = 'N';
public string LegalName
{
get { return legalName; }
}
public IEnumerable<string> Curves
{
get { return curves; }
}
public Entry(string legalName, IEnumerable<string> curves)
: this(legalName, curves, double.NaN, 'N') { }
public Entry(string legalName,
IEnumerable<string> curves,
double notional,
char seniriority)
{
this.legalName = legalName;
this.curves = curves;
this.notional = notional;
this.seniriority = seniriority;
}
}
}
}
Some thing similar to this should work
var haystack = new Pool().Constituents;
var indexedhaystack = haystack.Select((item, index)=> new {
item, index
});
var pool = new Pool()
{
Constituents = from l in indexedhaystack
select new Constituent()
{
//your stuff here
}
};
... extended ...
var constituents = new Pool().Constituents.Select((c, i) =>
new
{
Constituent = c,
Index = i
});
var items = from c in constituents
where !string.IsNullOrEmpty(c.Constituent.Name)
&& string.IsNullOrEmpty(c.Constituent.Curve)
let curves = new[]{
"EUR" + c.Index.ToString(),
"USD" + c.Index.ToString()
}
let match = new ConstituentMatch(){
new Group("High") {
new Entry(
c.Constituent.Name + " Ltd.",
curves),
new Entry(
c.Constituent.Name + " Inc.",
curves)
}
}
select new
{
Name = c.Constituent.Name,
Curves = curves,
Match = match
};
...
public class Constituent
{
public string Name { get; set; }
public string Curve { get; set; }
}
public class Pool
{
public List<Constituent> Constituents { get; set; }
}
public class Entry
{
public Entry(string entry, IEnumerable<string> curves)
{
}
}
public class Group : List<Entry>
{
public Group(string group) { }
}
public class ConstituentMatch : List<Group>
{
}
Language INtegrated Query is, as its name says, a technology for querying objects and data, not for modifying them.