Extending the String Class With Properties? - c#

I have an application where I need to populate a textbox with a company name and I have filled a custom AutoCompleteStringColection with all the available company names from the database. When a user enters changes the company name by typing and selecting from the list a new company name I need to have the id (Guid), of the selected company so I can do a lookup and get the rest of the company information. Because the company name is not guaranteed to be unique I cannot do a lookup on the name and expect to have the right record. I looked at extending the string class, but all I can find are examples that add methods. I tried that by adding a variable to store the id and methods to get and set the id, but when retrieving the id it is always the last id set. Can a property be added to a class by extending it? I have already changed what I was trying to do to do a lookup on the company name and display a list the user will choose from if multiple matches are returned, but I would still like to know if I can add a property this way in case it comes up again.

No, you cannot extend classes with properties. Additionally, String is sealed so you can't extend it by inheriting. The only recourse is to composition: encapsulate string in your own class.

It sounds like you should create your own class:
class Company {
public string Name {get;set;}
public override string ToString() {return Name;}
// etc
}
Now bind to a set of Company objects; the ToString override will ensure that the Name is displayed by default, and you can add whatever else you need. For more complex scenarios, you can use (for example) DisplayMember and ValueMember (of a combo-box) to point at different properties (rather than the default ToString).

You should use a ComboBox rather than a TextBox. Create a custom type that has your company name and id in it, making sure that it overrides ToString to return the company name. Add those custom types to the ComboBox rather than straight-up strings, and use AutoCompleteSource of ListItems.

I used Konrad's answer and for the sake of completeness I am posting my solution here. I needed to show my user an autocomplete list of company names, but since they could have multiple companies with the same name I needed the Guid id to find their choice in the database. So I wrote my own class inheriting from AutoCompleteStringCollection.
public class AutoCompleteStringWithIdCollection : AutoCompleteStringCollection
{
private List<Guid> _idList = new List<Guid>();
/*-- Properties --*/
public Guid this[int index]
{
get
{
return _idList[index];
}
}
public Guid this[string value]
{
get
{
int index = base.IndexOf(value);
return _idList[index];
}
}
/*-- Methods --*/
public int Add(string value, Guid id)
{
int index = base.Add(value);
_idList.Insert(index, id);
return index;
}
public new void Remove(string value)
{
int index = base.IndexOf(value);
if (index > -1)
{
base.RemoveAt(index);
_idList.RemoveAt(index);
}
}
public new void RemoveAt(int index)
{
base.RemoveAt(index);
_idList.RemoveAt(index);
}
public new void Clear()
{
base.Clear();
_idList.Clear();
}
}

Related

Show ToString of a Collection Wrapper Class in DataGridView

I have a class that has one of its properties being of type ObservableCollection<string>
public class SizeList
{
public string ID { get; set; }
public string Name { get; set; }
//public ObservableCollection<string> List { get; set; }
public ListEntryCollection List { get; set; }
}
During a unit test I return a list of SizeList and then show it in a DataGridView to check the results I am expecting, the data is fine but I am missing the field List in the DGV; only the ID and Name are shown, so I have made a wrapper class for the ObservableCollection<string> and overriden its .ToString() method:
namespace System.Collections.ObjectModel
{
using System.Collections.Generic;
public class ListEntryCollection : ObservableCollection<string>
{
public ListEntryCollection(IEnumerable<string> collection)
: base(collection)
{
}
public override string ToString()
{
return Count.ToString() + ((Count > 1) ? " Entries": " Entry");
}
}
}
But I am still not getting the List field in the DGV, so what am I doing wrong ?
Per Column Types in the Windows Forms DataGridView Control, the only property types for which bound columns are automatically generated are numbers, text, booleans, and images.
To display other types, you need to add the column manually to the DataGridView, or use a custom column type (and even then, you'll probably have to add it manually.)
A couple of options present themselves:
You could try adding a read-only property to SizeList to display the description of the list, and see if that will result in a column being automatically created.
You can try adding a column manually, which I believe you can do in the Form Designer if you click on the DataGridView. You will probably have to override a method or two, or use an event handler, in order to change the display from the default. (It's possible, though, that it will use the ToString override you created, in which case the problem is solved.)
Or, you could create a ListSummaryDataGridViewColumn class, that can represent a list by display a count of the items in it, and add one of those manually.

When using a class as key of dictionary: is there a possibility to specify which class property/ variable determines the key

I try to explain my question by using simplified source code.
The class I have is e.g.:
public class House
{
public House(...)
{
address = ...;
owner = ...;
}
public string address; //Unique variable
public string owner; //Not unique variable
}
At some point, I need a dictionary which has the "House" as key and e.g. a boolean as value.
E.g.
var doesTheHouseOwnerHaveDept= new Dictionary<House,bool>();
Then, I have the problem that the dictionary "doesTheHouseOwnerHaveDept" is - of course - full of duplicates since, by considering the address and owner, multiple unique "key pairs" exist if a person owns multiple houses.
Thus, is there a possibility to modify the class such that only the "owner" variable within the class "house" is used for specifying the key of the dictionary "doesTheHouseOwnerHaveDept"?
I.e., when an owner e.g. "Max" owns the house at address "A" and "B", then, first come, first serve like, only one "House"-instance will be added to the dictionary "doesTheHouseOwnerHaveDept".
I know that in the previous example, the problem could easily be solved in other more intuitional ways, but I did not have a better idea and wanted to avoid posting original source code.
Thanks a million for your support and effort! :)
If you want the owner (in this simplified code) to be the Key of your Dictionary you will need to override Equals and GetHashCode. It is important to override both otherwise it will not work.
Here an example of the House class:
If you create two houses with the same owner and try to add them to a dictionary where the Key is the House object it would give you an error
Edit
Here an importand edit from #l33t:
"Do not use a public field. Instead use a property with a private setter. Any value used in GetHashCode() must be immutable or your objects will get lost (in e.g. a dictionary), never to be found again."
public class House
{
public House(string address, string owner)
{
this.Address = address;
this.Owner = owner;
}
public string Address; //Unique variable
public string Owner
{
get;
private set; //Private setter so the owner can't be changed outside this class because it if changes and the object is already inside
// a dictionary it won't get notified and there will be two objects with the same 'Key'
}
public override bool Equals(object obj)
{
if (!(obj is House)) return false;
var toCompare = (House) obj;
return this.Owner == toCompare.Owner; //Just compare the owner. The other properties (address) can be the same
}
public override int GetHashCode()
{
return Owner.GetHashCode(); //Just get hashcode of the owner. Hashcode from the address is irrelevant in this example
}

EF-CF-Set 'ignored' property from another table value

I am using Entity Framework Code-First approach. Below is my sample Model.
public class LocalizableEntity
{
public int Id{get;set;}
// this property is 'Ignore'd. Need to set this.
public string Name{get;set;}
// this is the collection of 'Name's in all supported cultures.
public virtual ICollection<LocalizationText> LocalNames{get;set;}
}
Using fluent API, the 'Name' property will be ignored, like Ignore(t=>t.Name). My idea is to set the Name property from LocalNames collection by querying with a given culture ID. The LocalizationText type will look like below.
public class LocalizationText
{
public int Id{get;set;}
public string Text{get;set;}
public string Culture{get;set;}
}
I want to implement methods to SELECT the items in SINGLE, ALL and BY PREDICATE in my repository(please consider LocalizableEntities and LocalizationText are the DbSets), but with populating the Name property in one query.
GET SINGLE ITEM method
public LocalizableEntity GetById(int id)
{
var result=LocalizableEntities.Find(id); // selects the item
//the culture will be passed in by other way. Hard-coding here
result.Name=LocalizableEntities.LocalNames.Single(t=>t.Culture=="en-us");
return result;
}
But the above implementation will take two DB calls. I want to make this into one query/expression. I also need to do this when selecting in batch also, assigning value for Name over sequence.
Is this possible with single query? If yes, can anyone please guide me?
Thanks :)
Ignoring the entity model field kind of smells. Your design seems well suited to a ViewModel. So then assuming you have an entity model called LocalizationText and a ViewModel called LocalizableEntityVM you could do something like:
public LocalizableEntityVM GetById(int id, string culture)
{
var result=LocalizationText.Single(le => le.id && le.Culture == culture)
.Select(le => new LocalizableEntityVM
{
Name = le.Text
});
return result;
}

Validating a large dictionary of set strings with user input

I have a profile form that has a lot of user selections and I am sort of stumped on a good approach to validate what the user enters, when passing validation mapping those values to object properties.
For example I have a dictionary
public static Dictionary<string, string> objProfileSelections = new Dictionary<string, string>();
public static string MySelections(string key)
{
objProfileSelections.Add("1", "No Answer");
objProfileSelections.Add("3", "Less Than $25,000");
objProfileSelections.Add("5", "$35,000 to $50,000");
objProfileSelections.Add("7", "$50,000 to $75,000");
objProfileSelections.Add("9", "$75,000 to $100,000");
objProfileSelections.Add("11", "$100,000 to $150,000");
objProfileSelections.Add("13", "$150,000+");
objProfileSelections.Add("2", "No Answer");
objProfileSelections.Add("4", "Less Than $25,000");
objProfileSelections.Add("6", "$35,000 to $50,000");
objProfileSelections.Add("8", "$50,000 to $75,000");
objProfileSelections.Add("10", "$75,000 to $100,000");
objProfileSelections.Add("12", "$100,000 to $150,000");
objProfileSelections.Add("14", "$150,000+");
string item;
objProfileSelections.TryGetValue(key, out item);
return item;
}
Id like to pass in a list of key strings from the user and pass those items to populate an object. The issue is I don't know how to code it so it know which property to go to, I looked at reflection, but I couldn't find any examples that have a set dictionary of values that map to property names.
To make a bit more clear, when a user makes a selection it passes as a parameter in the dictionary, and the dictionary outputs the items. From key 1 comes value No Answer. If the user selected all the check boxes it would be value - (1,3,5,7,9,11,13). I need to extract those values when there is a matching key to a matching property. For example if the user clicks 1,5 but leaves the rest unchecked, how do I know which selections the user made? How do I get the program to know which property to populate based on the results?
*edit
some properties I would like it mapped to
public string MyAnnualIncome{ get; set; }
public List<string> InterestAnnualIncome{ get; set; }
So the first property would be taking one value, and the second property would be taking multiple values.
When a key matches a value comes out the dictionary, I would need the odd values going to MyAnnualIncome and the even values going to InterestAnnualIncome.
so no one is confused odd and even keys are set up for a purpose, odd numbers belonging to a certain group of properties and the even ones belonging to another based on the html selections (even being my selections, odd being what I am interested in)
*Update
Is there a way I can possibly use the keys like 1,3,5 and pass that into a list using the except extension method. Then take the results and use a method to convert the values from enumerated data types to strings?
Hopefully I understood your question.
I would add a small helper class (this is a solution which doesn't use reflection, but uses delegates instead):
public class PropertyModifier
{
private string text;
private Func<string> modifier;
public PropertyModifier(Func<string> modifier)
{
this.modifier = modifier;
}
public PropertyModifier With(string text)
{
PropertyModifier newModifier = new PropertyModifier(modifier);
newModifier.text = text;
return newModifier;
}
public void Modify()
{
modifier(Text);
}
}
Then I would rewrite your code and have the dictionary map to this class instead to string:
public static Dictionary<string, PropertyModifier> objProfileSelections = new Dictionary<string, PropertyModifier>();
public static MyUserProfile Profile; //Assuming this is the object you want to modify
public static string MySelections(string key)
{
PropertyModifier myIncome = new PropertyModifier(text => Profile.MyAnnualIncome = text);
PropertyModifier interestIncome = new PropertyModifier(text => Profile.InterestAnnualIncome.Add(text));
objProfileSelections.Add("1", myIncome.With("No Answer"));
objProfileSelections.Add("3", myIncome.With("Less Than $25,000"));
...
objProfileSelections.Add("2", interestIncome.With("No Answer"));
objProfileSelections.Add("4", interestIncome.With("Less Than $25,000"));
...
}
Then, when processing the user's selection, get the mapped PropertyModifier from the dictionary and call its Modify method.
I tried in this code to illustrate how you can modify the properties of the different classes that may compose a profile. Modifications are done by reflection only, i.e. just providing the class name, the property name that will vary in each class and the string value to be assigned to the property.
Not sure that it fits your expectations :(
Profile profile = new Profile() ;
profile.SetPropertyValue("hair","color","brown") ;
internal class Profile()
{
private Hair hair_ = new Hair();
private Job job_ = new Job ();
internal Hair hair { get { return hair_ ; } }
internal Job job { get { return job_ ; } }
private void SetPropertyValue(string profileItemName, string ItemPropertyName, string value)
{ // it is assumed that the different items (hair or job) of the Profile are accessible
// with a a property
// first find the Item object, i.e. hair or job
object itemObj = this.GetType().GetProperty(profileItemName).GetValue(this,null);
// assign to Item property the input value, e.g. hair.color=Brown
itemObj.GetType().GetProperty(ItemPropertyName).SetValue(itemObj, value, null);
}
}
internal class Hair()
{
private string color_ ;
private string style_ ;
internal string color { get { return color_ ; } set {color_ = value ; } }
internal string style { get { return style_ ; } set {style_ = value ; } }
}

In C#, does an overriden property return the stored value to the parent class?

I have a base page for an order form. Inside this base page are a few properties that are abstract. They are overriden in a child class. One property in particular is called CompanyName. It's a string. In the child class, I have added code that pulls the CompanyName from a collection of CompanyNames. Since the overriden property obtains a CompanyName, can the parent class access the value obtained by the child's class version of the method?
Here is a snippet of my parent class named OrderFormBasePage:
protected string GetNextInvoiceNumber()
{
using (NewUOCompany db = new NewUOCompany())
{
}
var model = new InvoiceModel();
return model.GetNextInvoiceNumber(CompanyID).ToString();
}
#region Properties
protected int CompanyID { get; }
protected abstract string CompanyName { get; }
protected abstract string OutputFilename { get; }
protected abstract string SourcePDFPath { get; }
#endregion
Here is a snippet of the child class named GetEuropeanSubmissionForm:
public partial class GetEuropeanSubmissionForm : OrderFormBasePage
{
#region Properties
protected override string CompanyName
{
get { return Constants.companyNames.EuropeanCompanyName; }
}
protected override string OutputFilename
{
get { return "Submission Form - Europe.pdf"; }
}
protected override string SourcePDFPath
{
get { return "~/pdf/" + OutputFilename; }
}
#endregion
}
So basically, when the user wants to download the European Form pdf, they are redirected to a GetEuropeanSubmissionForm page. The code behind will supply the right CompanyName and the right pdf. But the pdf needs to be modified to display the right CompanyName, CompanyID, and invoice number. I know how to do it by hardcoding a config file but this solution lets me manage the code in only one place instead of in many places. So if I want to write the code for the CompanyID retrieval inside of OrderFormBasePage, and if I want to search the database for the CompanyID that corresponds to the CompanyName pulled in GetEuropeanSubmissionForm, should OrderFormBasePage's CompanyName property now contain the CompanyName pulled by GetEuropeanSubmissionForm? I tried searching "C# overriden property returning value to parent class" but found no results. Thanks for any advice!
Yes, when the base class accesses the properties , it will get the values that are set in the parent class.
Check this example, especially the area property and usage of it in Shape.ToString() method.
https://msdn.microsoft.com/en-us/library/yd3z1377.aspx
Yes.
The whole point of overriding is that all calls to that member, no matter what type they're made through, call the overridden version.
This is the idea of polymorphic behavior, common denominator takes different shapes of behavior according to the actual instance behind it.

Categories