Extending a property and in meanwhile insert a new item - c#

This is my code:
var myList = myPage.News.Cast<MyNew>();
MyNew have somethings like 20 property (Name, Title, Date, Place, etc etc) but it miss one, the property (for example) Tel.
Can't recreate my whole structure (it also become from a DLL), so I'd like to faster add a property of MyNew called Tel, inside that list. So extend the class during the insert in a list.

No, but you could create an anonymous type that includes the original type plus your new column:
var myList = myPage.News
.Cast<MyNew>()
.Select( new { m => MyNew = m,
Tel = [formula for tel]
}
);

public class MyNewExtended: MyNew {
public String Tel { get;set; }
}
var myList = myPage.News.Cast<MyNewExtended>();
(but see Chris Sinclair's comment below)

You should be able to extend MyNew with a partial class like so:
public partial class MyNew
{
public int Tel { get; set; }
}
Tel will then be available like any other property.

Related

ObjectlistView Checkbox Issue

I have an issue trying to get a Checkbox working with ObjectListview.
My model looks like this:
public class object
{
public string name {get; set;}
public int age {get; set;}
public bool inuse {get; set;}
}
And I added a FastObjectListView via the Designer in Visual Studio to a Win Forms Application.
Then, I added the Columns and set the AspectName for each column to the Models Property (First column: AspectName: name, Second Column: AspectName: age, Third Column: AspectName: inuse).
Afterwards, I filled the ListView with this:
using (var context = new objectDb())
{
var objectlist = context.objects.ToList();
fastoLV_Clean.SetObjects(objectlist);
fastoLV_Clean.Refresh();
}
That works, and I can see my Database entries in the ListView.
Now I want to add a CheckBox column where someone can check or uncheck the items to delete them and I can not get the checkbox to work.
I have added a Column and set CheckBox to true, changed the CheckedAspectName of the ListView and now I can see the Checkboxes but nothing happens if I click them to check.
I think I'm on the completely wrong track, what do I have to do to make it work?
Thank you very much!!
I don't know a way with the ObjectListView to include any items which are not part of your model.
So then the simple way is to change your model to include a "Delete" property which you can then show in your ObjectListView.
Of course, this is not always possible! Especially if you are dealing with items that are written to/from Database or another persistence layer.
Then the trick is to write a derived class with you model being the base class and then you just add the delete column to this. But then you would need to convert from your Base to a derived class before showing in the ObjectListView.
The following code can help with that.
You keep your columns set-up as you have already done.
Assuming your (now base) class is defined like this
public class MyClass
{
public string name { get; set; }
public int age { get; set; }
public bool inuse { get; set; }
}
Your derived class inherits from this, adds the delete property and a new constructor
public class MySecondClass : MyClass
{
public bool Delete { get; set; }
public MySecondClass(MyClass other)
{
//Copy from MyClass
this.name = other.name;
this.age = other.age;
this.inuse = other.inuse;
//Set default for new properties
this.Delete = false;
}
}
Your code to retrieve the objects and set them then looks like this
using (var context = new objectDb())
{
var objectlist = context.objects.ToList();
//Now we need to convert to the derived class type
var secondlist = list.ConvertAll(x => new MySecondClass(x));
//Then we setobjects using this new list
fastoLV_Clean.SetObjects(secondlist);
}

Use C# Linq Lambda to combine fields from two objects into one, preferably without anonymous objects

I have a class setup like this:
public class Summary
{
public Geometry geometry { get; set; }
public SummaryAttributes attributes { get; set; }
}
public class SummaryAttributes
{
public int SERIAL_NO { get; set; }
public string District { get; set; }
}
public class Geometry
{
public List<List<List<double>>> paths { get; set; }
}
and i take a json string of records for that object and cram them in there like this:
List<Summary> oFeatures = reportObject.layers[0].features.ToObject<List<Summary>>();
my end goal is to create a csv file so i need one flat List of records to send to the csv writer i have.
I can do this:
List<SummaryAttributes> oAtts = oFeatures.Select(x => x.attributes).ToList();
and i get a nice List of the attributes and send that off to csv. Easy peasy.
What i want though is to also pluck a field off of the Geometry object as well and include that in my final List to go to csv.
So the final List going to the csv writer would contain objects with all of the fields from SummaryAttributes plus the first and last double values from the paths field on the Geometry object (paths[0][0][first] and paths[0][0][last])
It's hard to explain. I want to graft two extra attributes onto the original SummaryAttributes object.
I would be ok with creating a new SummaryAttributesXY class with the two extra fields if that's what it takes.
But i'm trying to avoid creating a new anonymous object and having to delimit every field in the SummaryAttributes class as there are many more than i have listed in this sample.
Any suggestions?
You can select new anonymous object with required fields, but you should be completely sure that paths has at least one item in each level of lists:
var query = oFeatures.Select(s => new {
s.attributes.SERIAL_NO,
s.attributes.District,
First = s.geometry.paths[0][0].First(), // or [0][0][0]
Last = s.geometry.paths[0][0].Last()
}).ToList()
Got it figured out. I include the X and Y fields in the original class definition. When the json gets deserialized they will be null. Then i loop back and fill them in.
List<Summary> oFeatures = reportObject.layers[0].features.ToObject<List<Summary>>();
List<Summary> summary = oFeatures.Select(s =>
{
var t = new Summary
{
attributes = s.attributes
};
t.attributes.XY1 = string.Format("{0} , {1}", s.geometry.paths[0][0].First(), s.geometry.paths[0][1].First());
t.attributes.XY2 = string.Format("{0} , {1}", s.geometry.paths[0][0].Last(), s.geometry.paths[0][1].First());
return t;
}).ToList();
List<SummaryAttributes> oAtts = summary.Select(x => x.attributes).ToList();

How to Cast List<T> To List<ClassName>

I am using generic method to fill my dropdown for all types
below is my code.
the entity type are as follow
public class Role
{
public string Id { get; set; }
public string Name { get; set; }
}
public class DropDown
{
public string Id { get; set; }
public string Name { get; set; }
}
i am able to fetch data successfully at
var data = DataFetcher.FetchData<T>();
private static void Main( string[] args )
{
List<DropDown> cities = BLL.GetDataList<City>();
List<DropDown> states = BLL.GetDataList<State>();
List<DropDown> roles = BLL.GetDataList<Role>();
}
public static class BLL
{
public static List<DropDown> GetDataList<T>() where T : class ,new()
{
var data = DataFetcher.FetchData<T>();
return data as List<DropDown>;
}
}
I knew this cast data as List<DropDown> will fail,thats why its returning null back to calling method,
How can i cast Generic list to List of Known Type?
You have to ask yourself: how do I want to convert T to DropDown? If you can't answer this, the answer is: you can't.
I guess your DropDown class has an object Value property, that holds the dropdown value, and you wish to assign the data entity to that property.
Then you can project the list of data entities to DropDowns as such:
var data = DataFetcher.FetchData<T>();
return data.Select(d => new DropDown { Value = d }).ToList();
As for your edit: so you have at least one type, the displayed Role, that has an Id and Name property. But type T doesn't guarantee this, so you'd need to introduce an interface:
public interface INamedIdentifyableEntity
{
string Id { get; set; }
string Name { get; set; }
}
And apply this to your entities. Then introduce it as a generic constraint and do the mapping:
return data.Select(d => new DropDown
{
Id = d.Id,
Name = d.Name,
}).ToList();
But you don't want this, as here you are tying these two properties to dropdowns. Tomorrow you'll want an entity with Code instead of Id and Text instead of Name, so you'll have to add more interfaces, more overloads, and so on.
Instead you might want to use reflection, where you can specify the member names in the call:
List<DropDown> cities = BLL.GetDataList<City>(valueMember: c => c.CityCode, displayMember: c => c.FullCityname);
And use these member expressions to look up data's values and fill those into the DropDown.
However, you're then reinventing the wheel. Leave out your DropDown class entirely, and leave the dropdown generation to the front end, in this case MVC:
var cities = DataFetcher.FetchData<City>();
var selectList = new SelectList(cities.Select(c => new SelectListItem
{
Selected = (c.Id == selectedCityId),
Text = c.FullCityName,
Value = c.CityCode,
});
Or:
var selectList = new SelectList(cities, "CityCode" , "FullCityName", selectedCityId);
One solution is to use AutoMapper.
First create a map between your models like this:
AutoMapper.Mapper.CreateMap<Role, DropDown>();
Do the same thing for City and State classes if you need to.
Then you can use AutpMapper to convert your objects to DropDown like this:
public static List<DropDown> GetDataList<T>() where T : class ,new()
{
var data = DataFetcher.FetchData<T>();
return data.Select(x => AutoMapper.Mapper.Map<DropDown>(x)).ToList();
}
If I understood the question correctly, you could use Linq as follows.
return data.Cast<DropDown>().ToList();

comparing objects and returning list

I have a class definition that looks like this:
public class MyObjectModel
{
public int ObjectID { get; set; }
//for when the user's data is split in 2 fields
public string FirstName { get; set; }
public string LastName { get; set; }
//for when the user's data is all in one field
public string FirstLastName { get; set; }
}
I have a list of these MyObjectModel and I want to sort them by name with a custom sort process because that involves checking if the data contains a LastName (in this case sort using the LastName) or just FirstLastName (in this case I'm going to break the string and sort on the second term, if there's one, or just the whole string if there's only one word.)
I'm not sure on two things:
should I use IComparer or IComparable?
Once it determines the order of the sort (I can do that), how do I make it so that the output of the method is a list of ints representing ObjectID.
Use Linq:
List<MyObjectModel> objects = new List<MyObjectModel>();
List<int> ids = objects.OrderBy(o => FunctionWhichReturnsNameForSort(o)).Select(o => o.ObjectID).ToList();
FunctionWhichReturnsNameForSort can be implemented in another class, or an extension, or as a member.
// should be in a static helper class
public static string NameForSort(this MyObjectModel obj)
{
if (!string.IsNullOrEmpty(obj.LastName)) return obj.LastName;
return obj.FirstLastName.Split(... // your splitting logic goes here
}
var ids = objects.OrderBy(o => o.NameForSort()).Select(o => o.ObjectID).ToList();
When you really need this strange double solution then you will run into this and similar problems more often. As a more general solution, consider putting the business logic for names in a few read-only properties:
//for when the user's data is split in 2 fields
public string FirstName { get; set; }
public string LastName { get; set; }
//for when the user's data is all in one field
public string FirstLastName { get; set; }
public string FullName
{
get { ... } // pick from LastName, FirstName, FirstLastName
}
public string SortName
{
get { ... } // pick from LastName, FirstLastName
}
Once it determines the order of the sort (I can do that), how do I make it so that the output of the method is a list of ints representing ObjectID
result = MyObjectList
.OrderBy(m => m.SortName) // sort on SortName
.Select(m => m.ObjectID) // select the Id
.ToList();
If this sorting is specific to one use case, it can be achieved using LINQ:
var sortedIds = models.OrderBy(SecondName).Select(m => m.ObjectId).ToList();
private static string SecondName(MyObjectModel model)
{
if (!string.IsNullOrWhitespace(model.LastName)) return model.LastName;
return model.FirstLastName.Split(' ').Last();
}
While you can use LINQ, as others have suggested, that would involve creating a brand new list, not mutating the existing list. That may or may not be preferable. If you want to sort the list itself that's easy enough too:
List<string> list = new List<string>(){"a","b","c"};
list.Sort((a,b)=> a.CompareTo(b));
Just take your list, call Sort, and pass in a lambda that takes two items and returns an integer indicating which is greater. In your case, just call some method on a and b to get a string and then use CompareTo or string.Compare on those two strings.

Inheriting object and auto populate

When I want to extend an existing Object I create my own and use inherits clause, and works fantastic... problem is when I want to use this new Object instead of the original, the populate part is a "pain".
is there any AUTO POPULATE way of doing this?
Original Object: Customer
My Object: CustomerWithGroup
public class CustomerWithGroup : Customer
{
public CustomerWithGroup() { }
public string GroupName { get; set; }
public string Fullname
{
get
{
return string.Format("{0} {1} {2}", firstname, middlename, lastname).Replace(" ", " ");
}
}
}
and I'm populating it like this:
customerswithgroup = new List<CustomerWithGroup>();
string groupname;
foreach (Customer c in customers)
{
groupname = customergroup.Find(x => x.customer_group_id == c.group_id).customer_group_code;
customerswithgroups.Add(
new CustomerWithGroup {
GroupName = groupname,
created_at = c.created_at, customer_id = c.customer_id, default_billing = c.default_billing, default_shipping = c.default_shipping, email = c.email, firstname = c.firstname, group_id = c.group_id, increment_id = c.increment_id, lastname = c.lastname, middlename = c.middlename, password_hash = c.password_hash, prefix = c.prefix, store_id = c.store_id, suffix = c.suffix, taxvat = c.taxvat, updated_at = c.updated_at, website_id = c.website_id });
}
It's a bunch of code! and you can imagine doing this for really big objects!
Ins't there a way of telling, like
Hei object, please load all the base members from this Object!
newCG = new CustomerWithGroup().LoadFromBase(c);
newCG.groupName = "my group";
customerswithgroup.Add( newCG );
Is there any trick we can use?
No, there is no easy way. You could use reflection and write a bunch of code to do that, but it would be a lot of work.
In my opinion you should rethink your design. Inheritance is not a good solution in this case, composition here is better, like so:
public class CustomerWithGroups
{
public CustomerWithGroups(Customer c) { Customer = c; }
public Customer Customer { get; private set; }
public string GroupName { get; set; }
public string Fullname
{
get
{
return string.Format("{0} {1} {2}", Customer.firstname, Customer.middlename, Customer.lastname).Replace(" ", " ");
}
}
}
You cannot easily do this automatically.
You could make a constructor or method in the derived class that takes an instance of the base class and copies all of the properties. (You'd still need to write it by hand, but you'd only need to write it once)
If you really want to do it automatically, you could use reflection to loop through the properties and make an expression tree that copies them from an original.
However, the best way is to use a has-a relationship, making CustomerWithGroups not inherit Customer and instead have a read-only Customer property of type Customer.

Categories

Resources