Avoiding repetitive job when dealing with many variables - c#

I'm looking for some advices how to deal with similar example problem:
string A;
string B;
string C;
string D;
...
void Initialize()
{
A = someObject.A.ToString();
B = someObject.B.ToString();
C = someObject.C.ToString("F");
D = someObject.D.ToString();
...
}
My class has a lot of numeric variables and I need to pass their values to these strings easily for large quantity of such variables. Let's say it is RPG stats based game and a lot of stats, factors etc. play here a role. Managing such a many variables by copy pasting is a pain.
Question: how can I simplify work with lots of variables.
I would like to know some solutions for this problem since I don't have any experience with it and I don't know anyone or any source to search for a solutions.
I personally thought about using some kind of structure, dicitonary or database.
EDIT: To be precise I've created a class called Character and it has a lot of properties like xp, life, gold etc. Now I want to do a GUI using class called Label that draw text on the screen, so I'm coding GUI class containing Label objects that on various events will react accordingly. For example I need to assign at the beginning to my labels specified text like:
Label life, gold, xp, etc;
life.text = Character.instance.Life.ToString();
gold.text = Character.instance.Gold.ToString();
xp.text = Character.instance.XP.ToString();
...

You should include more details in this question, what you exactly want to achieve.
From the information you provided, I assume you want to read the properties of someObject dynamically, execute ToString() on them and assign its value to some variables. That is a typical reflection assignment. You might want to read a chapter covering reflection on MSDN
If the assumption above is correct, you could do the following:
Dictionary<string, string> propertyValues = new Dictionary<string, string>();
// We access the type information via reflection. What properties your someObject has?
PropertyInfo[] propertyInfos = someObject.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var propertyInfo in propertyInfos)
{
// we get the value of the property, described by propertyInfo, from our someObject
object value = propertyInfo.GetValue(someObject, null);
if (value != null)
{
// do your special type handling here and execute ToString()
if(value.GetType() == typeof(int))
propertyValues[propertyInfo.Name] = ((int)value).ToString("F");
if(value.GetType() == ...)
else
propertyValues[propertyInfo.Name] = value.ToString();
}
}
// so if your someObject had a property A you can access it as follows:
string A = propertyValues["A"];
// or you loop the dictionary and do some suff with it (which makes much more sense):
foreach(var keyValuePair in propertyValues)
Console.WriteLine("Property {0} = {1}", keyValuePair.Key, keyValuePair.Value);

It's a little hard for us to say without seeing your exact design/requirements, but a simple way to do this which handles many situations is to store the object itself, rather than copying its properties or fields.
For example, in your version you might have:
private int A;
private string B;
private double C;
public void Initialize(DataObject data)
{
A = data.A;
B = data.B;
C = data.C;
}
public void DoSomething() //Just an arbitrary method using the data
{
return B + " " + A.ToString();
}
Whereas, you could more simply do:
private DataObject _data;
public void Initialize(DataObject data)
{
_data = data;
}
public void DoSomething() //Just an arbitrary method using the data
{
return _data.B + " " + _data.A.ToString();
}

Depending on how the values get into 'someObject', a first step into having less code would be to define the properties to be String, doing the conversion from int to String in the get accessor method. Even though this just moves the ToString() to a different location, it will reduce the code each time you go to get the value.

Related

Clean Way to Merge Two Typed C# Objects Based on Given Sequence

I have two lists, each containing two objects of a class called TestData
TestData td1_a = new TestData("td1", "val11_a", null, "val13_a");
TestData td1_b = new TestData("td1", "val11_b", "val12_b", null);
TestData td2_a = new TestData("td2", "val21_a", "val22_a", null);
TestData td2_b = new TestData("td2", "val21_b", null, "val23_b");
List<TestData> list_a = new List<TestData>() {td1_a, td2_a};
List<TestData> list_b = new List<TestData>() {td1_b, td2_b};
TestData is defined as
public class TestData {
public string DataName;
public string Value1;
public string Value2;
public string Value3;
public TestData(string name, string val1, string val2, string val3) {
DataName = name;
Value1 = val1;
Value2 = val2;
Value3 = val3;
}
}
Note that the two lists each contain two TestData objects whose DataName values are "td1" and "td2"
How to merge the two lists such that the final result would be a single list whose members are two TestData objects where the objects with the same DataName merged and the value of the later override the value of the earlier if it is not null in a clean way?
So if I do mergeList(list_a, list_b), the result would be a list with members of:
TestData td1_merged = new TestData("td1", "val11_b", "val12_b", "val13_a");
TestData td2_merged = new TestData("td2", "val21_b", "val22_a", "val22_b");
That is, _b is replacing _a whenever possible
and if I reverse the order mergeList(list_b, list_a), the result would be a list having member of:
TestData td1_merged = new TestData("td1", "val11_a", "val12_b", "val13_a");
TestData td2_merged = new TestData("td2", "val21_a", "val22_a", "val22_b");
Where _a is replacing _b instead.
At this moment, this is the best I can do with LINQ aggregate:
private List<TestData> mergeList(List<TestData> list_1, List<TestData> list_2) {
return list_1.Concat(list_2) //combining list_1 and list_2 depends on the given sequence
.GroupBy(td => td.DataName) //making groups based on DataName
.Select(g => g.Aggregate(g.First(), (a, b) => { //merge the values of the elements
if (b.Value1 != null) //tedious way of giving the conditions!
a.Value1 = b.Value1;
if (b.Value2 != null)
a.Value2 = b.Value2;
if (b.Value3 != null)
a.Value3 = b.Value3;
return a;
})).ToList();
}
It works fine except for the fact that to make conditions for overriding when not null, I have to write it once for each object. Is there a cleaner way to do it?
Edited:
I do this because I encounter a problem where an object can be partially defined by separated developers on different files. My job is to create, but not to duplicate, the objects created in a smart way such that if the object is defined in more than one file, the later file additional definition will override the early ones, but not overriding everything (what has been defined in the earlier file remains whenever there is no update).
Example, if in one of the file, it is defined:
Chip_ResetSource.bits =[hw_pin=0, power_on=1, missing_clock=2, watchdog=3, software_force=4, comparator=5, convert_start_0=6].
And elsewhere, it is also defined:
Chip_ResetSource =type=uint8;policy=read;
And somewhere else,
Chip_ResetSource =address=2500;unit=count;formula=1;max=255;min=0;
Then I just need to combine all of them. But if in another (later) file there is additional info about Chip_ResetSource:
Chip_ResetSource =address=2501;
Then, while all other info of Chip_ResetSource must remain the same after the third info Chip_ResetSource =address=2500;unit=count;formula=1;max=255;min=0;, its address property must be changed from 2500 to 2501 due to the fourth info.
So, given that problem, I think if I can just create one method to read all the given property at the instantiation and then another method to cleanly merge when other file is read, that will be great!
One approach to simplify your problem would be to use a Dictionary instead of multiple strongly typed classes.
In that case, you would simply add values to the dictionary, and it would update (overwrite) any existing keys with new values:
static void Apply(IDictionary<string, string> properties, string input)
{
// split by semicolon
var props = input.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// add/merge each key-value pair into the dictionary
foreach (var t in props)
{
var tokens = t.Trim().Split('=');
var key = tokens[0];
var value = tokens[1];
// this will add a new value, or update the existing one
properties[key] = value;
}
}
This would store each value as a separate key-value pair, and you would use this similar to:
var properties = new Dictionary<string, string>();
Apply(properties, "type=uint8;policy=read;");
Apply(properties, "address=2500;unit=count;formula=1;max=255;min=0;");
Apply(properties, "address=2501;");
// dump the contents to screen to see what we've got now
Console.WriteLine(string.Join(";", properties.Select(x => $"{x.Key}={x.Value}")));
Regarding your .bits example, it's not clear whether you would treat .bits as a single string property and overwrite it completely in case it's found in a different file, or update its child properties like it's a nested object.
In this latter case, a simple approach would be to store the child properties exactly the same way, but perhaps prefix their key with "bits.", which would functionally be equivalent to:
Apply(properties, "bits.hw_pin=0; bits.power_on=1; bits.missing_clock=2;");

Iterate through properties and values of an object returned via a linq query on a domain model

I have a custom entity in a relational database that I have mapped to the CLR via a domain model. So by using the following statement, I can pull in an entity from my database into memory via a LINQ query on the domain model, like so;
var inspection = (from i in dbContext.New_testinspectionExtensionBases
where i.New_testinspectionId == currentInspection
select i).First();
There are properties/fields on this entity that I need access to, I need to be able to determine the property/field name as well as it's value. I want to loop through these items in memory, and write out their names and values to the console.
I tried using this approach, but couldn't figure out how to correct the syntax (Nor am I sure that GetProperties is the correct method to use, GetFields wasn't returning anything for some reason so I assumed this was the way to go) but it doesn't really matter since all i need is read access to the value;
var inspectionReportFields = inspection.GetType().GetProperties();
// I called this inspectionReportfields because the entity properties correspond to
// form/report fields I'm generating from this data.
foreach (var reportField in inspectionReportFields)
{
var value = reportField.GetValue();
Console.WriteLine(reportField.Name);
Console.WriteLine(value);
}
Is there an easier way to get the property/field value when utilizing a domain model like EF or openaccess? If not, am I going about it the right way? And lastly, if so, how do I fix the syntax in the value variable declaration?
Here are some sample fields/properties from the code generated by the domain model, for reference;
private int? _new_systemGauges;
public virtual int? New_systemGauges
{
get
{
return this._new_systemGauges;
}
set
{
this._new_systemGauges = value;
}
}
private int? _new_systemAlarm ;
public virtual int? New_systemAlarm
{
get
{
return this._new_systemAlarm;
}
set
{
this._new_systemAlarm = value;
}
}
I assume that you're trying to define a general-purpose way to "dump" an object without knowing anything about its structure. If so, then you are going about things the correct way. You use reflection (GetType() and the associated Type class methods) to inspect the object and return its information.
The reason GetFields() didn't return anything is that you likely did not supply the right binding flags. In particular, if you call the overload that doesn't take any parameters, you only get back public fields; if you want private fields you need to ask for them specifically.
In your case, GetFields(BindingFlags.NonPublic) would give you back the _new_systemGauges and _new_systemAlarm fields, while GetProperties() would give you back the New_systemAlarm and New_systemAlarm properties.
The other key element you missed is that the data you are getting back is the type metadata; it defines the structure of the class, and not any particular instance. If you want to know what the value of a property for a specific instance is, you need to ask for that:
foreach (var prop in obj.GetType().GetProperties())
{
Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(obj, null));
}
One you have one of the PropertyInfo elements from the type's metadata, you can ask for that property value on any instance of that type. It doesn't have to be the same instance that you originally used. For example:
var objs = somelist.Where(x => x.Id == 1);
foreach (var prop in objs.First().GetType().GetProperties())
{
int x = 0;
foreach (var obj in objs)
{
if (prop.PropertyType.Name.Equals("Int32"))
{
int val = (int)prop.GetValue(obj, null);
Console.WriteLine("Obj #{0}: {1} = 0x{2:x8}", x++, prop.Name, val);
}
else if (prop.PropertyType.Name.Equals("Decimal"))
{
int val = (decimal)prop.GetValue(obj, null);
Console.WriteLine("Obj #{0}: {1} = {2:c2}", x++, prop.Name, val);
}
else
{
Console.WriteLine("Obj #{0}: {1} = '{2}'", x++, prop.Name, prop.GetValue(obj, null));
}
}
}
Technically you should check the result of GetIndexParameters to see if a property is indexed or not; the null parameter to GetValue is actually an array of index values.
To convert the value you get back you can either use typecasts, or if you want to be a bit more flexible, use the Convert class's methods. The difference is, for example, if you have a short property, GetValue() will return a boxed short, which you cannot then typecast as an int; you have to unbox it to a short first. Using Convert.ToInt32() will perform all of the needed steps to get an int value out of any property that is convertible to an integer.
Converting between reference types is easier since you can just use is and as for that; those work just like you'd expect with "reflected" property values.
GetProperties indeed is the correct method.
To get rid of the compiler error, change your code to this:
var value = reportField.GetValue(inspection, null);
You need to pass the instance from which you want to obtain the value, as a PropertyInfo object is not bound to any specific class instance.
Please consider following the standard .NET naming rules.
This would lead to the following:
NewSystemAlarm instead of New_systemAlarm
newSystemAlarm or _newSystemAlarm instead of _new_systemAlarm
NewTestInspectionExtensionBases instead of New_testinspectionExtensionBases
NewTestInspectionId instead of New_testinspectionId
If you are using OpenAccess you always have the complete information about your model classes at your disposal. The information there is retrieved from your mapping which means that you needn't reflect over your classes (no overhead).
Just browse trough context.Metadata.PersistentTypes for all of your classes mapping information.

Is there a nice way to avoid using reflection to populate my virtual ListView?

I have a ListView in virtual mode, and the underlying data is being stored in a List<MyRowObject>. Each column of the ListView corresponds to a public string property of MyRowObject. The columns of my ListView are configurable during runtime, such that any of them can be disabled and they can be reordered. To return a ListViewItem for the RetrieveVirtualItem event, I have a method similar to:
class MyRowObject
{
public string[] GetItems(List<PropertyInfo> properties)
{
string[] arr = new string[properties.Count];
foreach(PropertyInfo property in properties)
{
arr[i] = (string)property.GetValue(this,null);
}
return arr;
}
}
The event handler for RetrieveVirtualItem looks similar to:
private void listView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
e.Item = new ListViewItem(_virtualList[e.ItemIndex].GetItems(_currentColumns));
}
Maybe not surprisingly, benchmarking shows that this method is significantly slower than an implementation that accessed properties directly in a hardcoded order, and the slowdown is just significant enough that I would like to find a better solution.
The most promising idea I've had is to use an anonymous delegate to tell the MyRowObject class how to directly access the properties, but if it's possible I couldn't get the semantics right (given the name of a property stored in a string, is there a way I can write a closure to directly access that property?).
So, is there a nice way to avoid using reflection to populate my ListView without losing any functionality?
The open source extension of ListView is off limit because of company policy.
You could use these 2 functions
private List<Func<T, string>> BuildItemGetters<T>(IEnumerable<PropertyInfo> properties)
{
List<Func<T, string>> getters = new List<Func<T, string>>();
foreach (var prop in properties)
{
var paramExp = Expression.Parameter(typeof(T), "p");
Expression propExp = Expression.Property(paramExp, prop);
if (prop.PropertyType != typeof(string))
propExp = Expression.Call(propExp, toString);
var lambdaExp = Expression.Lambda<Func<T, string>>(propExp, paramExp);
getters.Add(lambdaExp.Compile());
}
return getters;
}
private string[] GetItems<T>(List<Func<T, string>> properties, T obj)
{
int count = properties.Count;
string[] output = new string[count];
for (int i = 0; i < count; i++)
output[i] = properties[i](obj);
return output;
}
Call the BuildItemGetters (sorry for the name, couldn't think of anything ;) once with a list of properties you want to get from the rows. Then just call the GetItems for each row. Where obj is the row and the list is the one you got from the other function.
For T just use the class name of your Row, like:
var props = BuildItemGetters<MyRowObject>(properties);
string[] items = GetItems(props, row);
ofcourse, only call the build when the columns change
BindingSource and PropertyDescriptor are more elegant techniques for performing manual data-binding, which is more-or-less what you're doing with the ListView when it's in VirtualMode. Although it generally uses reflection internally anyway, you can rely on it to work efficiently and seamlessly.
I wrote a blog article recently which explains in detail how to use these mechanisms (although it's in a different context, the principles are the same) - http://www.brad-smith.info/blog/archives/104
Take a look at Reflection.Emit. With this, you can generate code on the fly that accesses a specific property. This CodeProject article has an interesting description of the mechanism: http://www.codeproject.com/KB/cs/fast_dynamic_properties.aspx.
I haven't throughly reviewed the code of the project, but my first impression is that the basic idea looks promising. However, one of the improvements I would make is that some of the pieces of the class should be static and shared, for example InitTypes and the created dynamic assembly. For the rest, it looks like it fits what you're looking for.
I don't know enough about c# to tell you if that is possible, but I'll go and hack my way with something like this:
once, i will try to get 'delegate pointers' for every member that I need, and will do that through reflection - if it were c++, those pointers would be vtable offsets for property getter function
will create a map with string->pointer offset
will use the map to call the getter function directly through the pointer.
Yes, it seems like a magic, but i guess that someone with enough CLR/MSIL knowledge can shed the light on that if it is remotely possible.
Here is another variant caching the get methods for each property.
public class PropertyWrapper<T>
{
private Dictionary<string, MethodBase> _getters = new Dictionary<string, MethodBase>();
public PropertyWrapper()
{
foreach (var item in typeof(T).GetProperties())
{
if (!item.CanRead)
continue;
_getters.Add(item.Name, item.GetGetMethod());
}
}
public string GetValue(T instance, string name)
{
MethodBase getter;
if (_getters.TryGetValue(name, out getter))
return getter.Invoke(instance, null).ToString();
return string.Empty;
}
}
to get a property value:
var wrapper = new PropertyWrapper<MyObject>(); //keep it as a member variable in your form
var myObject = new MyObject{LastName = "Arne");
var value = wrapper.GetValue(myObject, "LastName");

What is the best way to store static data in C# that will never change

I have a class that stores data in asp.net c# application that never changes. I really don't want to put this data in the database - I would like it to stay in the application. Here is my way to store data in the application:
public class PostVoteTypeFunctions
{
private List<PostVoteType> postVotes = new List<PostVoteType>();
public PostVoteTypeFunctions()
{
PostVoteType upvote = new PostVoteType();
upvote.ID = 0;
upvote.Name = "UpVote";
upvote.PointValue = PostVotePointValue.UpVote;
postVotes.Add(upvote);
PostVoteType downvote = new PostVoteType();
downvote.ID = 1;
downvote.Name = "DownVote";
downvote.PointValue = PostVotePointValue.DownVote;
postVotes.Add(downvote);
PostVoteType selectanswer = new PostVoteType();
selectanswer.ID = 2;
selectanswer.Name = "SelectAnswer";
selectanswer.PointValue = PostVotePointValue.SelectAnswer;
postVotes.Add(selectanswer);
PostVoteType favorite = new PostVoteType();
favorite.ID = 3;
favorite.Name = "Favorite";
favorite.PointValue = PostVotePointValue.Favorite;
postVotes.Add(favorite);
PostVoteType offensive = new PostVoteType();
offensive.ID = 4;
offensive.Name = "Offensive";
offensive.PointValue = PostVotePointValue.Offensive;
postVotes.Add(offensive);
PostVoteType spam = new PostVoteType();
spam.ID = 0;
spam.Name = "Spam";
spam.PointValue = PostVotePointValue.Spam;
postVotes.Add(spam);
}
}
When the constructor is called the code above is ran. I have some functions that can query the data above too. But is this the best way to store information in asp.net? if not what would you recommend?
This is a candidate for an immutable struct that "looks like" an enumeration:
(Also, I noticed you used the same id value for two of them, so I fixed that...
You can use the following just as you would an enumeration...
PostVoteTypeFunctions myVar = PostVoteTypeFunctions.UpVote;
and real nice thing is that this approach requires no instance storage other than a 4-byte integer (which will be stored on stack, since it's a struct). All hard-coded values are stored in the type itself... of which only one will exist per AppDomain...
public struct PostVoteTypeFunctions
{
private int id;
private bool isDef;
private PostVoteTypeFunctions ( ) { } // private to prevent direct instantiation
private PostVoteTypeFunctions(int value) { id=value; isDef = true; }
public bool HasValue { get { return isDef; } }
public bool isNull{ get { return !isDef; } }
public string Name
{
get
{ return
id==1? "UpVote":
id==2? "DownVote":
id==3? "SelectAnswer":
id==4? "Favorite":
id==5? "Offensive":
id==6? "Spam": "UnSpecified";
}
}
public int PointValue
{
get
{ return // Why not hard code these values here as well ?
id==1? PostVotePointValue.UpVote:
id==2? PostVotePointValue.DownVote
id==3? PostVotePointValue.SelectAnswer:
id==4? PostVotePointValue.Favorite:
id==5? PostVotePointValue.Offensive:
id==6? PostVotePointValue.Spam:
0;
}
}
// Here Add additional property values as property getters
// with appropriate hardcoded return values using above pattern
// following region is the static factories that create your instances,
// .. in a way such that using them appears like using an enumeration
public static PostVoteTypeFunctions UpVote = new PostVoteTypeFunctions(1);
public static PostVoteTypeFunctions DownVote= new PostVoteTypeFunctions(2);
public static PostVoteTypeFunctions SelectAnswer= new PostVoteTypeFunctions(3);
public static PostVoteTypeFunctions Favorite= new PostVoteTypeFunctions(4);
public static PostVoteTypeFunctions Offensive= new PostVoteTypeFunctions(5);
public static PostVoteTypeFunctions Spam= new PostVoteTypeFunctions(0);
}
It is difficult to tell from the fragment of code you have posted whether you expose any of the data outside the class.
If not, then this would work. However, if not, there are several issues:
If you are exposing the List, you should only ever return a copy of it as an IEnumerable<PostVoteType> using the yield keyword.
Make sure your PostVoteType is immutable, otherwise the references can be changed and the fields used might be altered
Looking at your code, it looks like you're just trying to create a set of objects that really just put the enum PostVotePointValue into some sort of list. I.e. you already have what you need defined in just the enum itself. I would encourage you to not define the same information in two places (this data store you are asking for and the enum). This is common mistake I see people make. They create a lookup table/list, then create an enum that mirrors the rows of the table and that means they have to modify two places for any change to the list.
If PostVotePointValue isn't an enum but just some constants or if there is more info you are planning on packing in, then this isn't relevant.
Here's some examples of how to work with Enums as 'lists' from http://www.csharp-station.com/Tutorials/Lesson17.aspx
// iterate through Volume enum by name
public void ListEnumMembersByName()
{
Console.WriteLine("\n---------------------------- ");
Console.WriteLine("Volume Enum Members by Name:");
Console.WriteLine("----------------------------\n");
// get a list of member names from Volume enum,
// figure out the numeric value, and display
foreach (string volume in Enum.GetNames(typeof(Volume)))
{
Console.WriteLine("Volume Member: {0}\n Value: {1}",
volume, (byte)Enum.Parse(typeof(Volume), volume));
}
}
// iterate through Volume enum by value
public void ListEnumMembersByValue()
{
Console.WriteLine("\n----------------------------- ");
Console.WriteLine("Volume Enum Members by Value:");
Console.WriteLine("-----------------------------\n");
// get all values (numeric values) from the Volume
// enum type, figure out member name, and display
foreach (byte val in Enum.GetValues(typeof(Volume)))
{
Console.WriteLine("Volume Value: {0}\n Member: {1}",
val, Enum.GetName(typeof(Volume), val));
}
}
}
You should be able to adapt the above into an approach that will give you a list that you can use for databinding if you need it.
I am wondering why you could not just use a simple enum for this?
public enum PostVoteType
{
UpVote = 0,
DownVote = 1,
SelectAnswer = 2,
Favorite = 3,
Offensize = 4,
Spam = 5
}
"Never" is a very hard word indeed.
In your particular case you are asserting that not only is your PostVoteType data absolute and immutable, but so is the container collection. Frankly I don't believe you can know that, because you are not the business (your interpretation of requirement is imperfect) and you are not psychic (your knowledge of the future is imperfect).
I would suggest that you always store any data which cannot be expressed as an enumeration in some kind of repository. Where you expect relational and/or transactional and/or mutable needs that means a database, if you expect high read to write ratio that can be a config file (which I believe this case should be).
Edit: In terms of memory persistance I agree with others that the cache is the best place to store this, or rather in a domain object which is backed by cache.
Aside: your construction of PostVoteTypes is horrible - strongly suggest you want a refactor :)
If it doesn't change, is commonly accessed, and is the same for all users, then the .NET cache is the proper place. Have a property that yields these values. Inside, the property checks the cache for this list and returns the stored value; otherwise, it constructs it from scratch, adds to the cache, and returns the value.
This should still probably be configured in the database though, even if you cache it. I imagine that you'll need to use these value in conjunction with other data in your DB.
When you need to often access the same data, and need not to store it into the underlying database, and that this data is about the same in every situation the application may encounter, then I suggest to use caching. Caching is born from these requirements. Caching is normally the fastest way to providing data as they are always kept in memory or something similar to ease and to make the access easier by the application.
Here is a nice caching tool provided with Microsoft Enterprise Library, the Caching Application Block.
I think it is worth to take the time to learn how to use it effectively.
create a singleton class.

c# looping object creation

I'm very new with c#, and was previously attempting to ignore classes and build my small program structurally more similar to PHP. After reaching a road block, I'm trying to start over and approach the problem properly OO. I'm taking a long file, and in a loop, every time certain conditions are met, I want to make a new object. How can I have it create a new object, without having to specify a unique name?
Referral ObjectName = new Referral(string, string, int);
Secondly, once this is done, and the strings & int set their appropriate object properties, how can i unique-ify the class by one property, and then sort the class by another?
I'm sorry if these are basic questions, I have spent a large, large amount of time first trying to figure it out on my own with google, and a textbook. If only C# would allow multi-dimensional arrays with different types!
Thank you so much!
PS. I do mean to extract a list of unique objects.
All these answers, while helpful, seem to involve creating a shadow set of IEnumerables. Is there no way to do this with the class itself?
Trying the first solution, provided by Earwicker, adding each object to a List from within the loop, when I try to Write a property of the element to the console, i get the ClassName+Referral. What could I be doing wrong?--solved. still needed .property
still working. . .
C# does allow untyped arrays. All objects are derived ultimately from object, so you use an array or container of objects. But it's rarely necessary. How many types of object do you have?
Within the loop block, you can create an object exactly as you do in that line of code (except with the syntax fixed), and it will be a new object each time around the loop. To keep all the objects available outside the loop, you would add it to a container:
List<Referral> referrals = new List<Referral>();
// in the loop:
Referral r = new Referral(str1, str2, num1);
referrals.Add(r);
Suppose Referral has a numeric property called Cost.
referrals.Sort((l, r) => l.Cost - r.Cost);
That sorts by the cost.
For ensuring uniqueness by some key, you may find it easier to pick a more suitable container.
Dictionary<string, Referral> referrals = new List<Referral>();
// in the loop:
Referral r = new Referral(str1, str2, num1);
referrals[str1] = r;
This stores the referral in a "slot" named after the value of str1. Duplicates will overwrite each other silently.
First, you're going to need to spend some time familiarizing yourself with the basics of the language to be productive. I recommend you take a little time to read up on C# before getting in too deep - otherwise you'll spend a lot of your time spinning your wheels - or reinventing them :)
But here's some info to get you started.
Typically, in C# you create classes to represent elements of your program - including those that are used to represent information (data) that your program intends to manipulate. You should really consider using one, as it will make data manipulation clearer and more manageable. I would advise avoiding untyped, multi-dimensions array structures as some may suggest, as these rapidly become very difficult to work with.
You can easily create a Referall class in C# using automatic properties and a simple constructor:
public class Referall
{
// these should be named in line with what they represent...
public string FirstString { get; set; }
public string AnotherString { get; set; }
public int SomeValue { get; set; }
public Referall( string first, string another, int value )
{
FirstString = first;
AnotherString = another;
SomeValue = value;
}
}
You can add these to a dictionary as you create them - the dictionary can be keyed by which ever property is unique. Dictionaries allow you to store objects based on a unique key:
Dictionary<string,Referall> dict = new Dictionary<string,Referall>();
As you process items, you can add them to the dictionary:
Referall ref = new Referall( v1, v2, v3 );
// add to the dictionary, keying on FirstString...
dict.Add( ref.FirstString, ref );
If you need to sort items in the dictionary when you're done, you can use LINQ in C# 3.0:
IEnumerable<Referall> sortedResults =
dict.Values.OrderBy( x => x.AnotherString );
You can sort by multiple dimension using ThenBy() as well:
IEnumerable<Referall> sortedResults =
dict.Values.OrderBy( x => x.AnotherString )
.ThenBy( x => x.SomeValue );
List<Referral> referrals = new List<Referral>();
for (...)
{
referrals.Add(new Referral(string1, string2, number1));
}
Then, if you're using Linq (which I highly suggest), you can do this:
IEnumerable<Referral> sorted = referrals.OrderBy(x => x.string1).ThenBy(x => x.string2);
Otherwise, you can use the Sort() method on List<Referral>.
You can create an object without a reference, but you won't have any access to it later:
new Referral(string, string, int);
If you wish to put them in an array/list, these different types need to have a common base class. This is called polimorfism, which is a very important concept in OO programming.
You cannot ignore classes while using c#. Don't resist the change!
Do you really not need to create a class here? Do you really not need to give it a name? C# does allow loose typing, but type safety is a good thing.
I don't fully understand what you're trying to do. But maybe LINQ is what you're looking for. There's tons of documentation around, but as a quick 'teaser' have a look at the 101 Linq samples on MSDN
C# includes a wonderful feature called "iterator blocks". What you want to do is use the yield keyword to create an Enumerable of your Referal object, something like this (not that I'm making the file format and property names up, because you didn't share that):
public class Referral
{
public Guid id { get; private set; } // "uniquify"
public int ReferringId { get; set; }
public string ReferrerText { get; set; }
public string ReferrerDescription { get; set; }
private Referral()
{
id = new Guid();
}
private Referral(string Text, string Description, int ReferringId) : this()
{
this.ReferrerText = Text;
this.ReferrerDescription = Description;
this.ReferringId = ReferringId;
}
public static IEnumerable<Referral> GetReferrals(string fileName)
{
using (var rdr = new StreamReader(fileName))
{
var next = new Referrer();
int state = 0;
string line;
while ( (line = rdr.ReadLine() ) != null)
{
switch (state)
{
case 0:
next.ReferrerText = line;
state = 1;
break;
case 1:
next.ReferrerDescription = line;
state = 2;
break;
case 2:
next.ReferringId = int.Parse(line);
yield return next;
next = new Referral();
state = 0;
break;
}
}
}
}
}
Now you want to sort the referrals and presumable enumerate over them for some purpose. You can do that easily like this:
foreach (var referral in Referral.GetReferrals(#"C:\referralfile.txt").OrderBy( r => r.Text ) )
{
OutputReferral(referral);
}

Categories