Replacing boilerplate code C# with inteligent methods (maybe by using pointers?) - c#

We are writing a data repository and we have a data model that has quite a few fields.
And on the top of that, we have data accessors that return requested field value of the data object with the given id.
However, the problem is that we have to write a method for every single field which results in a ton of boilerplate code that literally differs in the field accessed and sometimes the return value type.
Here is the code:
[Serializable]
struct MyItem
{
public readonly int Id;
public int SomeInt;
public float SomeFloat;
// in real-life scenario there are many more fields here
}
// we need this container because our JSON parser needs one
class MyItemDataList
{
public List<MyItem> Items = new List<MyItem>();
}
class Example
{
readonly MyItemDataList _myList = new MyItemDataList();
public float GetSomeFloat(int id)
{
for (int i = 0; i < _myList.Items.Count; i++)
{
int currentId = _myList.Items[i].Id;
if (id == currentId)
return _myList.Items[i].SomeFloat;
}
return 0; // just so it compiles for the sake of this example
}
public int GetSomeInt(int id)
{
for (int i = 0; i < _myList.Items.Count; i++)
{
int currentId = _myList.Items[i].Id;
if (id == currentId)
return _myList.Items[i].SomeInt; // all of this methods differ only in the field accessed and value type returned
}
return 0; // just so it compiles for the sake of this example
}
// in real-life scenario there are many more fields here
}
One solution would be to write a switch (if-else) statement and simply in addition to id pass also the field requested but that gives us a very long switch and many comparisons (not a big deal but still).
Ideally, what I would like to achieve is some sort of a template method (maybe with use of pointers) that based on the field requested simply shift the pointer to the desired address and returns the bytes that correspond to the requested field. But how to do it in C#?

You can use generics and accept a Func<MyItem, T>. No need to use pointers, which are considered unsafe in C#.
class Example
{
readonly MyItemDataList _myList = new MyItemDataList();
public T GetSomeProperty<T>(int id, Func<MyItem, T> propertySelector)
{
for (int i = 0; i < _myList.Items.Count; i++)
{
int currentId = _myList.Items[i].Id;
if (id == currentId)
return propertySelector(_myList.Items[i]);
}
return default(T);
}
}
Usage:
For example, if you want to get SomeFloat:
GetSomeProperty(someId, x => x.SomeFloat)
The method could also be implemented with LINQ:
public T GetSomeProperty<T>(int id, Func<MyItem, T> propertySelector)
=> _myList.Items.Where(x => x.Id == id)
.Select(propertySelector)
.FirstOrDefault()

Replace the list against a dictionary.
public class MyItemDataList
{
public Dictionary<int, MyItem> Items { get;} = new Dictionary <int, MyItem>();
}
Create an extension method that accesses the dictionary for convenience
public static MyItem GetItem(this Dictionary<int, MyItem> dictionary, int id) => dictionary.TryGetValue(id, out var item)? item : null;
Usage
var #float = Items.GetItem(2)?.SomeFloat ?? 0.0;

Related

C# how to return 1 row from List<T> object passed as parameter

I need to return one row of List from my function Selectus.
So I pass to the function Selectus object that reflects database table fields and I need to return one row which match the parameter looking_for:
public static List<T> Selectus<T>(string looking_for)
{
//all select data
var db = OrmLiteBaza().Open();//opening database
var select_all_list = db.Select<T>();//getting all data for <T> object works fine
db.Dispose();
//try to select one row - here I have trouble:
var prop = typeof(T).GetProperties();//properties of passed <T> object
var list_selected_record = from records in select_all_list where prop[1].Name == looking_for select records;//tryin to select one record from <T> object as in looking_for variable
return list_selected_record.ToList();//here one record should be returned
}
I do not know how to select one row from the list assuming that T parameter is vary. In SelectusT> method I want to pass as T different objects which reflect fields in database table rather than creatinig separate methods for each select. e.g. call Selectus, where object passed is public class ProductCodes { public int ID { get; set; } public string SapIndex { get; set; } public string SapName { get; set; } }. Then I want to call another Selectus<ProductTypes> for another table etc... So I want to write generic/overall method and use it universally for all types of my objects which reflects the fields of few database tables. The SapIndex property is always in the same place of all objects...
Using prop[1] is incredibly fragile. Who says that the property you're currently interested in is always going to be in second place? What if someone adds another property tomorrow? What if not every T that you use have the same property in the second place on its list of properties? It is quite unclear what your actual goal is here and why you've taken the reflection route.
You would be better off using inheritance or interface implementation here. I'm going to use an interface in this answer, but either would work.
For the sake of clarity, let's assume there is a Code field in all your possible lists, and this is the property you're trying to match with.
Define a reusable interface:
public interface ICodeEntity
{
string Code { get; }
}
Apply your interface to all of the classes that you intend to use for your Selectus method.
public class Person : ICodeEntity
{
public string Code { get; set; }
// And other properties
}
public class Document : ICodeEntity
{
public string Code { get; set; }
// And other properties
}
Add a generic type constraint that limits the use of T only to types that implement your interface.
public static List<T> Selectus<T>(string code)
where T : ICodeEntity
You can now write your code in a way that it relies on the type in question having a Code property, and the compiler will help enforce it.
var db = OrmLiteBaza().Open();
var list = db.Select<T>().ToList();
db.Dispose();
return list.Where(item => item.Code == code).ToList();
Usage examples:
List<Person> peopleWithCodeABC = Selectus<Person>("ABC");
List<Person> documentsWithCodeXYZ = Selectus<Document>("XYZ");
// This will fail if Animal does not implement ICodeEntity
var compilerError = Selectus<Animal>("ABC");
I might not understand fully what you want, but instead of string looking_for you could pass in a Func<,> delegate which acts as a selector.
Something like:
public static List<TField> Selectus<T, TField>(Func<T, TField> selector)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
var list_selected_record = select_all_list.Select(selector); // 'using System.Linq;'
return list_selected_record.ToList();
}
Then I believe it could be called like this:
var list_one = Selectus((ProductCodes x) => x.SapIndex);
var list_two = Selectus((ProductTypes x) => x.SapIndex);
var list_three = Selectus((ProductCodes x) => x.SapName);
With this syntax I leave out the <ProductCodes, string> generic arguments to the method since they can be inferred.
Hmm, maybe you want it in the opposite dimension. You could do:
public static List<T> Selectus<T>(Func<T, bool> predicate)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
var list_selected_record = select_all_list.Where(predicate); // 'using System.Linq;'
return list_selected_record.ToList();
}
with:
var list_one = Selectus((ProductCodes x) => x.SapIndex == "ABC");
var list_two = Selectus((ProductTypes x) => x.SapIndex == "ABC");
var list_three = Selectus((ProductCodes x) => x.SapName == "DaName");
or:
var list_one = Selectus<ProductCodes>(x => x.SapIndex == "ABC");
var list_two = Selectus<ProductTypes>(x => x.SapIndex == "ABC");
var list_three = Selectus<ProductCodes>(x => x.SapName == "DaName");
But if it is going to always be the "same" property, like always x.SapIndex (but for different types of x), then Flater's answer looks good.
Otherwise, if you insist, your reflection approach should be possible. Use propety's name, not its index! Let me try:
public static List<T> Selectus<T>(string looking_for)
{
var db = OrmLiteBaza().Open();
var select_all_list = db.Select<T>();
db.Dispose();
const string prop_name = "SapIndex";
var prop = typeof(T).GetProperty(prop_name); // can blow up for bad T
var list_selected_record = select_all_list
.Where(x => (string)(prop.GetValue(x)) == looking_for); // 'using System.Linq;'
return list_selected_record.ToList();
}
with:
var list_one = Selectus<ProductCodes>("ABC");
var list_two = Selectus<ProductTypes>("ABC");
you can change code to return just one element
public static T Selectus<T>(string looking_for)
{
//all select data
var db = OrmLiteBaza().Open();//opening database
var select_all_list = db.Select<T>();//getting all data for <T> object works fine
db.Dispose();
//try to select one row - here I have trouble:
var prop = typeof(T).GetProperties();//properties of passed <T> object
var list_selected_record = from records in select_all_list where prop[1].Name == looking_for select records;//tryin to select one record from <T> object as in looking_for variable
return list_selected_record.FirstOrDefault();//here one record should be returned
}

How can I get a unique id for a List<T>

I have a List<T>, where T is a class that has an int field for an id. How is the best way to get a unique id value that has not been used in any of the objects in the List<T>?
How is this procedure normally coded? Is there a data type that can help with this or do I need to store the largest id value?
EDIT
How about when I get an id for an object that is 1. I then delete the object from the List. When I create a new object, I would like the unique id to be 2. In this situation, is there any better way than to store the last unique id?
Thanks.
For that approach I'd write an inherited class of List<T> which holds the logic, so you wouldn't need to implement it everywhere you access the list.
You can even leave it generic if you have a minimum interface which has the Id value.
interface IWithId {
int Id { get; set; }
}
class CustomList<T> : List<T> where T : class, IWithId {
private lastUsedId = 1;
public void AddObjectWithAutomaticId(T newObject) {
newObject.Id = lastUsedId++;
base.Add(newObject);
}
public T GetElementById(int id) {
return base.SingleOrDefault(p => p.Id == id);
}
}
The Remove method would still work as before. The class stores the last used Id, independent what you remove. The Add method is also still available, when you want to add an object with a given Id and not auto-fill it.
I agree with the comment that a GUID would suit you as an id property. If, however, you need to use an int then I suggest a new class.
The problem with inheriting List<T> is that you would have to override multiple methods to ensure that things such as Add(), AddRange(), Insert() can't add duplicate ids and update the stored maximum id. It would be easy to miss one.
I would use a class which doesn't inherit anything, but uses a dictionary internally. This won't have all the same methods as a List<T>, but that's not necessarily a bad thing - it saves mistakes being made and you can have a ToList() method for when they want to query it as if it was a List<T>.
Using part of a previous answer to ensure that T has an Id property gives:
interface IHasId {
int Id { get; set; }
}
class AutoIdList<T> where T : class, IHasId {
private readonly IDictionary<int, T> _dictionary = new Dictionary<int, T>();
//Using this list ensures you don't duplicate ids even
//for an item added with an explicit id then removed
private IList<int> _historicalIds = new List<int>();
private int highestAutoGeneratedId = 0;
public List<T> ToList() {
return _dictionary.Values.ToList();
}
public void Add(T item, bool generateId) {
if (generateId) {
highestAutoGeneratedId = NextId();
T.Id = highestAutoGeneratedId;
}
Add(T);
}
public void Replace(T item) {
_dictionary[item.Id] = item;
}
public void Remove(T item) {
_dictionary.Remove(item.Id);
}
private void Add(T item) {
if (_historicalIds.Contains(T.Id)) {
//throw an appropriate exception
} else {
_historicalIds.Add(T.Id);
_dictionary.Add(T.Id, T);
}
}
private int NextId() {
var id = highestAutoGeneratedId + 1;
while (_historicalIds.Contains(id)) {
id++;
}
return id;
}
//More methods to simulate AddRange, Insert, etc if required. Leave if not.
//Should all have simple logic but require checking of Id if adding anything
//Also need logic to maintain the list of used ids
}

How to create a method similar to ForEach

This is purely academic, but how would I create a method like the ForEach?
Say if I wanted to do something like the following:
SomeTenumerable.MyOwnFunction(x =>
{
x.Id = 0;
x.Order_Id = 0;
});
Note: I've only just got familiar with func<T,TResult>, so I'm not sure if it's the same thing.
Extra points if you can tell me the proper name/label of what I'm trying to achieve, I'm guessing it's some sort of delegate?
Demo here - https://dotnetfiddle.net/v7JKoo
.Each extension I use regularly - taken from http://extensionmethod.net/csharp/ienumerable-t/each-t
public static void Each<T>(this IEnumerable<T> items, Action<T> action)
{
if (items == null) return;
foreach (var item in items)
action(item);
}
Example:
var items = new List<Item>();
// populate items
items.Each(item => item.DoSomething());
Yes you are passing in a delegate (here it is an Action) to perform on each item
PS if you are looking to return items look at linqs .Where or .Select
I think what you want to do is create an extension method (MSDN)
ForEach is a method in the List class (you can see the code here). Since you cannot add a method to the class, you can create an extension method that lives in your project but can be used as it was part of the original List class.
Let's say your items use this interface
public interface IYourInterface
{
int Id;
int Order_Id;
}
You create a static method in a static class:
static class HelperMethods
{
public static void ResetAll(this List<IYourInterface> collection)
{
collection.ForEach(x =>
{
x.Id = 0;
x.Order_Id = 0;
});
}
}
And then use the method on any instance of List.
var collection = new List<IYourInterface>();
collection.ResetAll();
var otherStuff = new List<string>();
// This won't work because because List<string> cannot
// be converted to List<IYourInterface>
// otherStuff.ResetAll();
Add Property class
Public MyClass
{
public static int Id {get;set;}
public static int Order_Id{get;set;}
}
You can set it like this
IEnumerable<MyClass> myclass = new IEnumerable<MyClass>(
{
Id = 0;
Order_Id = 0;
});
You can query through, serach throw etc.
See this question, Here The question itself not the anwer.

List custom class members and type

This seems like the most basic thing ever but somehow I couldnt find the answer and couldnt figure it out.
Lets say I have a custom class:
public class WineCellar
{
public string year;
public string wine;
public double nrbottles;
}
Now I would like a function:
WineCellar ex = new WineCellar();
ex.members();
This should return: year, wine, nrbootles.
And:
ex.members().types();
Should return: string, string, double
I guess on the same note, lets say you have one instance {2010, Rioja, 6}. Is there syntax that returns these by indexing? i.e.
ex[1]
or
ex.{1}
that returns 2010?
Sorry for the basic question.
As Michelle said in the comments, this sounds like a wrong approach to a bigger problem.
However, if you do need this kind of things, you can get the using reflection:
//returns a list of propertyInfo objects for the class
// with all kinds of usefull information
public List<PropertyInfo> GetMemberInfos()
{
return this.GetType().GetProperties().ToList();
}
//returns a list of property names
public List<string> GetMemberNames
{
return this.GetType().GetProperties().Select(pi => pi.Name).ToList();
}
//returns a list of names of the property types
public List<string> GetMemberTypeNames
{
return this.GetType().GetProperties().Select(pi => pi.PropertyType.Name).ToList();
}
//indexer that uses the property name to get the value
//since you are mixing types, you can't get more specific than object
public object this[string property]
{
get { return this.GetType().GetProperty(property).GetValue(this); }
set { this.GetType().GetProperty(property).SetValue(this, value); }
}
//indexer that uses the property index in the properties array to get the value
public object this[int index]
{
get { return this.GetType().GetProperties()[index].GetValue(this); }
set { this.GetType().GetProperties()[index].SetValue(this, value); }
}
Note that all of these methods are very slow, because in general, reflection is slow. You can try to cache some thing to speed it up.
Also, the last method is downright dangerous. It will (try to) read and write to an array that does not have a guaranteed order. In fact, the documentation specifies:
The GetProperties method does not return properties in a particular
order, such as alphabetical or declaration order. Your code must not
depend on the order in which properties are returned, because that
order varies.
For example, if you change your class to:
public class WineCellar
{
public string year;
public string region;
public string wine;
public double nrbottles;
}
and you were used to using winecellar[1] = "Pinot Noir" that will most likely now update the region property, instead of the wine property.
This is how you would implement Members method (In case if you wanted property names as strings)
public List<string> Members()
{
List<string> propNames = new List<string>();
foreach (var prop in typeof(WineCellar).GetProperties())
{
propNames.Add(prop.Name);
}
return propNames;
}
And this is how you would implement Types (In same case)
public List<string> Types()
{
List<string> propTypes = new List<string>();
foreach (var prop in typeof(WineCellar).GetProperties())
{
propTypes.Add(prop.PropertyType.ToString());
}
return propTypes ;
}
And the last thing if you want to get values of the parameters like this ex[n] you can just make a simple indexer in you class like this
public string this[int n]
{
get
{
int current = 0;
foreach (var prop in typeof(WineCellar).GetProperties())
{
if (current == n)
return prop.GetValue(this, null).ToString();
current++;
}
return null;
}
}
but for these methods to work you should change your variables into properties like this
public class WineCellar
{
public string Year { get; set; }
public string Wine { get; set; }
public double Nrbottles { get; set; }
}
You can use reflection
foreach (var prop in typeof(WineCellar).GetProperties())
{
if (prop.PropertyType == typeof(double) || prop.PropertyType == typeof(double?))
{
}
}
to get the value, you can do:
prop.GetValue(obj);

DataBind to ICollection<T>

My program should read and process data from legacy flat files.
I read the data into private ICollection<transaction> transactions;
public class transaction
{
public int transactionNum;
public DateTime transactionDate;
public int orderNum;
public string customerName;
public Decimal amount;
}
How do I create a DataSource to this ICollection<T> (or a LINQ query of it), so that I can DataBind several control values to it?
Note: I have minimal LINQ knowledge. In the past, I could just drag a database table into my application.
From your comment:
On the ASP.NET form, I have a CheckBoxList named customerCheckL. Upon
loading the data file, the code should populate customerCheckL.Items
with the list of distinct customer names. How do I do that?
customerCheckL.DataSourceID = ???
That makes more sense. You could implement an EqulityComparer<transactions> class which compares by customer:
public class TransactionCustomerComparer : IEqualityComparer<transaction>
{
public bool Equals(transaction x, transaction y)
{
if (x == null || y == null) return false;
return x.customerName == y.customerName;
}
public int GetHashCode(transaction obj)
{
if (obj == null) return int.MinValue;
return obj.customerName.GetHashCode();
}
}
(Note that you can use this method in all Enumerable methods that allow to pass a custom comparer)
Then you can use Distinct to get a unique list. You just have to set the DataSource, DataTextField and DataValueField and DataBind the CheckBoxList.
var customerComparer = new TransactionCustomerComparer();
customerCheckL.DataSource = transactions.Distinct(customerComparer);
customerCheckL.DataTextField = "customerName";
customerCheckL.DataValueField = "transactionNum";
customerCheckL.DataBind();

Categories