how do i refactor this code? - c#

i have .net 3.5 and i would like to make a generic method. how do i refactor this code?
case (int)Enums.SandwichesHoagies.Cheeses:
if (this.Cheeses.Where(x => x.Id == product.ProductId).SingleOrDefault() == null)
{
var newCheese = new Cheese
{
Id = product.ProductId,
Name = product.Name,
PriceValue = product.Price.HasValue ? (double)product.Price.Value : 0.00
};
this.Cheeses.Add(newCheese);
}
else
{
foreach (var cheese in this.Cheeses.Where(cheese => cheese.Id == product.ProductId))
{
this.Cheeses.Remove(cheese);
break;
}
}
foreach (var cheese in Cheeses) cheese.Type = string.Empty;
if (this.Cheeses.Count > 0) Cheeses.First().Type = "Cheeses:";
break;
case (int)Enums.SandwichesHoagies.Meats:
if (this.Meats.Where(x => x.Id == product.ProductId).SingleOrDefault() == null)
{
var newMeat = new Meat
{
Id = product.ProductId,
Name = product.Name,
PriceValue = product.Price.HasValue ? (double)product.Price.Value : 0.00
};
this.Meats.Add(newMeat);
}
else
{
foreach (var meat in this.Meats.Where(meat => meat.Id == product.ProductId))
{
this.Meats.Remove(meat);
break;
}
}
foreach (var meat in Meats) meat.Type = string.Empty;
if (this.Meats.Count > 0) Meats.First().Type = "Meats:";
break;

Assuming two things:
Meat and Cheese inherit from Ingredient or implement IIngredient
The Meats and Cheeses collections are IList<T>
Here we go:
private void OuterMethod()
{
switch(something)
{
case (int)Enums.SandwichesHoagies.Cheeses:
HandleCase(product, this.Cheeses);
break;
case (int)Enums.SandwichesHoagies.Meats:
HandleCase(product, this.Meats);
break;
}
}
private void HandleCase<T>(Product product, List<T> list) where T : Ingredient, new()
{
if(list.Any(i => i.Id == product.ProductId))
{
list.Add(new T {
Id = product.ProductId,
Name = product.Name,
PriceValue = product.PriceValue ?? 0.0;
});
}
else
{
list.RemoveAll(i => i.Id == product.ProductId);
}
//NOTE: this part seems like a bad idea. looks like code smell.
foreach (var i in list)
{
i.Type = string.Empty;
}
if (list.Count > 0)
{
list.First().Type = "Cheeses:";
}
}

At initial glance, you have some common properties you access, Id, Name, PriceValue, and Type. That looks like a base class or interface to me. With that, you could start by refactoring your code into a method
void YourMethod<T>(List<T> list, Product product) where T : IProduct, new()
// IProduct being your interface or base class
In which case, where you refer to this.Meats or this.Cheeses, you would instead refer to list, and where you refer to instances of Meat or Cheese, you simply refer to T.
See how far that gets you and refactor further.

Hard to know your exact requirements without knowing the types (and base types/interfaces) used. I'm going to assume you're using some kind of ORM which spits out partial classes anyway.
First requirement to make this easy to work with, is that Meat and Cheese share a common interface (or abstract class). This should be something basic like this.
interface IProduct {
int Id { get; set; }
String Name { get; set; }
Double PriceValue { get; set; }
}
The assumption that partial classes are used makes it easy to extend your class to use this interface.
partial class Cheese : IProduct { }
I find it interesting that you have a different kind of Product which has different field names, but almost the same features. Should you perhaps keep the names the same as the above interface and make this also derived from the interface? Anyway, assuming what you have is something like this.
class Product {
int ProductId { get; set; }
String Name { get; set; }
Price? Price { get; set; }
}
The first thing you wanna do is use the Factory Pattern to create a specific product.
public class ProductFactory {
public T Create<T>(Product product)
where T : IProduct, new() {
return new T {
Id = product.ProductId,
Name = product.Name,
PriceValue = product.Price.HasValue
? (double)product.Price.Value
: 0.00
};
}
}
The new() constraint requires a parameterless constructor in your Cheese and Meat classes. I assume this is no problem. You just need to call .Create<Cheese>(product);
The next parts, I would need to assume that your Cheeses and Meats objects (or properties), also share a common class (ICollection<IProduct>), or you could define your own for particular needs.
public class ProductCollection : ICollection<IProduct> { ... }
A generic method to check if a product exists
Boolean ContainsProduct<T>(ProductCollection<T> collection, Product product)
where T : IProduct {
return collection.Where(x => x.Id == product.Id).SingleOrDefault != null;
}
I'm skeptical of your idea of calling .Remove inside a foreach loop. Modifying a collection can cause problems for the enumerator being used to loop through it. I would find a better approach to that if it's a concern.

Related

How to use LINQ to query a [key] property using generic types?

Let's say I have a class:
public class Customer
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
And now I want to create a generic Get() method that might query Customer or any one of several other classes that also have a [key] field defined.
public T Get<T>(int id)
{
string json = DoSomething(); // <-- making it easy for this post
List<T> items = JsonConvert.DeserializeObject<List<T>>(json);
return items.FirstOrDefault(i => i. ????? = id);
}
I'm not sure how to use Linq to generically specify the [key] field.
Thanks!
Hope this helps:
public interface IBase
{
int Id { get; }
}
public class Customer : IBase
{
public string Name { get; set; }
public int Id { get ; set ; }
}
public T Get<T>(int id) where T : IBase
{
string json = DoSomething(); // <-- making it easy for this post
List<T> items = JsonConvert.DeserializeObject<List<T>>(json);
return items.FirstOrDefault(i => i.Id == id);
}
Just implement the interface IBase in all other classes.
For what is worth I think using contracts is a better way to solve this. But in case you or someone else actually need to check for the attribute here's the answer:
public static T Get<T>(int id)
{
string json = DoSomething(); // <-- making it easy for this post
List<T> items = JsonConvert.DeserializeObject<List<T>>(json);
return items.FirstOrDefault(
item => (int)item.GetType()
.GetProperties()
.FirstOrDefault(
p => Attribute.IsDefined(p, typeof(KeyAttribute))
).GetValue(item) == id
);
}
As far a this part of your question:
I'm not sure how to use Linq to generically specify the [key] field.
The attribute is KeyAttribute you can know that by navigating to the definition (pressing F12 if you're using VS or checking the docs in case your editor doesn't support this feature.
Things to consider:
this is using Reflection reasonably heavily, so it will never have the best performance. That being said you can cache the result from GetProperties() somewhere for faster lookups.
It's hardcoding the cast to int but it appears that's what you're after.
If the collection is null it'll throw an exception.

How to get items from generics using expression?

I have an Ability class which looks like this
L1.
public class Ability
{
public int Id { get; set; }
public string Name {get; set;}
}
There are also many more enumlike classes that have Id and Name. So im writing Generic class to have less work later with them.
L2.
public class EnumRepository<TEnum>where TEnum : class
{ ... }
One method od said class looks like this:
L3.
public IEnumerable<SelectListItem> ToSelectListItem(
Expression<Func<TEnum, IEnumerable<Tuple<string, int>>>> text = null)
{
IQueryable<TEnum> query = dbSet;
var ret = new List<SelectListItem>();
if (text != null)
{
var res = query.SelectMany(text);
foreach (var tuple in res)
{
ret.Add(new SelectListItem()
{
Text = tuple.Item1,
Value = tuple.Item2.ToString()
});
}
}
return ret;
}
But I wore sth that I dont know how to use...
L4.
ret.Abilities = _unitOfWork.AbilityRepository
.ToSelectListItem( !what goes here?! )
Here are my questions:
What to put into metod argument in L4. to make it work?
Is there better way to do this?
Is it worth to do it?
In my old aproach I wrote ToSelectListItems in each class of this type. And using it was simple, like this ret.Abilities = Ability.ToSelectListItems() <- static method. But I had to do write this code in every class = hard to maintain and dumb way of doing things.
Assuming I understand your problem correctly, here goes:
What to put into metod argument in L4. to make it work?
Assuming for some reason you want to go ahead with your setup (please see below), you'd have to do something along those lines:
ret.Abilities =
_unitOfWork.AbilityRepository
.ToSelectListItem(item => new[] { new Tuple<String, int> (
(YourAbilityClass)item.Id,
(YourAbilityClass)item.Name)) };
which is slightly counterproductive, as you'd need to maintain part of your repository logic in every call.
Is there better way to do this?
Define better :). The way I would approach is as follows:
1) Define a new base class for all your entities, something like
public class BaseClass
{
public int Id { get; set; }
public String Name { get; set; }
}
and have all your relevant entities inherit from it:
public class Ability : BaseClass
{
}
(alternatively use a common interface - that depends on your design, so I can't make an informed suggestion here)
2) Then constraint your repositories to use BaseClass, like so:
public class EnumRepository<TEnum>where TEnum : BaseClass { ... }
3) Finally you can have
public IEnumerable<SelectListItem> ToSelectListItem()
{
return dbSet.Select(bc => new SelectListItem()
{
Text = bc.Name,
Value = bc.Id.ToString()
})
.ToArray();
}
and call it like so:
ret.Abilities = _unitOfWork.AbilityRepository.ToSelectListItem();
Is it worth to do it?
It's always hard to make fool-proof comments against someone else's design, if we're only shown a very small percent of it. Make your own decision - I do believe my suggestion might be a bit simpler in the long run, assuming it fits your needs.

Fluent interface building different concrete types

I need some suggestions on how to build a fluent interface acting as a Builder, responsible for returning different concrete types depending on the methods called.
Imagine that I need to create one of the following types using my ProductBuilder (fluently): Product, ServiceProduct, PackagedProduct (both derived from Product).
I'm thinking of using a fluent syntax like this (other suggestions are more than welcome):
To create a Product:
var product = new ProductBuilder()
.Create("Simple product")
.WithPrice(12.5)
To create a ServiceProduct
var product = new ProductBuilder()
.Create("Service product")
.WithPrice(12.5)
.AsServiceProduct()
.ServiceProductSpecificMethods...()
And PackagedProduct with a call to AsPackagedProduct() instead of AsServiceProduct() etc. You get the idea.
I haven't found a sample that shows best practices on this. Only samples where the final build returns the same type.
Any suggestions?
I see two options here.
If there are a finite number of products that are fixed, and not designed to be extended, then just create a Create method for each product:
var product = new ProductBuilder()
.CreateSimple()
.WithPrice(12.5);
var product = new ProductBuilder()
.CreateService()
.WithPrice(12.5)
.ServiceProductSpecificMethods...();
If you don't want (or can't have) ProductBuilder to know all of the types of products, then I would use generics:
public class Product {}
public class SimpleProduct : Product {}
public class ServiceProduct : Product {}
var product = new ProductBuilder<SimpleProduct>()
.WithPrice(12.5);
Here's a starting place for the design to follow:
public class Product
{
public decimal Price { get; set; }
}
public class SimpleProduct : Product { }
public class ServiceProduct : Product
{
public string Service { get; set; }
}
public class ProductBuilder<T> where T : Product, new()
{
private List<Action<T>> actions = new List<Action<T>>();
public T Build()
{
T product = new T();
foreach (var action in actions)
{
action(product);
}
return product;
}
public void Configure(Action<T> action)
{
actions.Add(action);
}
}
public static class ProductExtensions
{
public static ProductBuilder<T> WithPrice<T>(this ProductBuilder<T> builder, decimal price)
where T : Product
{
builder.Configure(product => product.Price = price);
return builder;
}
public static ProductBuilder<T> WithService<T>(this ProductBuilder<T> builder, string service)
where T : ServiceProduct
{
builder.Configure(product => product.Service = service);
return builder;
}
}
If I got you correctly I would use generics here so I can write something like:
var product = new ProductBuilder()
.Create<Serviceproduct>()
.WithPrice(12.5)
.ServiceProductSpecificMethods...()
You may also add Build method before calling specific service methods so it will actually create final product:
var product = new ProductBuilder()
.Create<Serviceproduct>()
.WithPrice(12.5)
.Build()
.ServiceProductSpecificMethods...()

Adding elements together across inherited arrays, LINQ

Following up on a previous question, here is my general class structure..
Combine Elements in a List based on Type and Summate their Values, LINQ
I am trying to combine the items using their respective .Add methods, but because of Entity Framework considerations, I can only deal with base types (Not interfaces).
using System.Linq;
using System.Collections.Generic;
interface Item<T>
{
T Add(T item);
}
abstract class Item
{
public ItemType Type;
public int Value;
}
class SubItemOne : Item, Item<SubItemOne>
{
public int Additional { get; set; }
public SubItemOne Add(SubItemOne item)
{
// ..
}
}
class SubItemTwo : Item, Item<SubItemTwo>
{
public int MoreData { get; set; }
public int OtherData { get; set; }
public SubItemTwo Add(SubItemTwo item)
{
// ...
}
}
class SubItemThree : Item, Item<SubItemThree>
{
public int StillOtherData { get; set; }
public int SecondaryData { get; set; }
public int TertiaryData { get; set; }
public SubItemThree Add(SubItemThree item)
{
// ...
}
}
class ItemType
{
public string Name;
}
class Test
{
public static void Main()
{
List<ItemType> types = new List<ItemType>();
types.Add(new ItemType { Name = "Type1" });
types.Add(new ItemType { Name = "Type2" });
types.Add(new ItemType { Name = "Type3" });
List<Item> items = new List<Item>();
for (int i = 0; i < 10; i++)
{
items.Add(new SubItemOne
{
Type = types.Single(t => t.Name == "Type1"),
Additional = i
});
}
for (int i = 0; i < 10; i++)
{
items.Add(new SubItemTwo
{
Type = types.Single(t => t.Name == "Type2"),
MoreData = 10,
OtherData = i + 10
});
}
for (int i = 0; i < 10; i++)
{
items.Add(new SubItemThree
{
Type = types.Single(t => t.Name == "Type3"),
SecondaryData = 1000,
StillOtherData = 1874,
TertiaryData = i * 10
});
}
List<Item> combined = new List<Item>();
// create a list with 3 items, one of each 'type', with the sum of the total values of that type.
// types included are not always known at runtime.
// I am trying to invoke the .Add Method on the items so that they can be collatted together. However
// they all return as the base type.
}
}
The problem is that you're going to have to deal with the interfaces at a higher level, and thus won't be able to do so generically (i.e., using the generic type arguments). You're going to have to define a non-generic interface (even if it's in addition to your current generic interface) that these classes implement in order to do what you're after. Item<SubItemOne> is no more related to Item<SubItemTwo> in terms of assignment compatibility than string is to DateTime.
If you must do it this way, then you'll have to use reflection. This should do the trick:
Dictionary<ItemType, Item> sum = new Dictionary<ItemType, Item>();
foreach (var item in items)
{
Item currSum;
if (sum.TryGetValue(item.Type, out currSum))
{
sum[item.Type] = (Item)item.GetType().GetInterfaces().Single(
i => i.Name == "Item").GetMethod("Add")
.Invoke(currSum, new object[] { item });
}
else
{
sum.Add(item.Type, item);
}
}
List<Item> combined = sum.Values.ToList();
To detail on how the problem was solved. I would like to thank both people who assisted with this answer, (also I want to thank jarret, from my previous question involving the linq query) for helping me to get the resolution entirely.
I have found both solutions to run substantially well, though I do not like the Microsoft.CSharp.dll library staring at me in The Resources folder (I know you're there, even if I collapse you! Don't try to deny it!)
In all, LINQ continues to amaze me, but I was shocked and astounded that dynamic worked more than anything. To test, I threw a "NotImplementedException" in each of the three derivitive classes "Add" methods and ran the entire execution, when the compiler broke out to show the Exception, it was in the appropriate class. This tested true in both cases.
Additionally, this showed that parameters are in fact different from names when it comes to implementation initialization where reflection is concerned. I tested the same for creating an interface IItem and IItem<T> and got the same results. (Additionally, IItem`1 also yielded the same results when IItem<T> was the implemented interface).
Each time I get an answer from Stackoverflow, it continues to amaze and astound me that no matter how much I think I know, there are so many people that know more, but not only that, that they are browsing the same resource sites that I am, and willing to answer such piddly questions that eat up their time and resources. Thanks again to all of you who helped!
Using Adam Robinson's Method, I approached it from this angle.
var grouped = items.GroupBy(i => i.Name);
grouped.ForEach(x => {
x.ForEach(e => {
// results handled here
// assumes that all objects inheriting "Item" implement IItem, which contracts "Add" method.
e.GetType().GetInterfaces().First(i => i.Name == "IItem").GetMethod("Add").Invoke(e, new object[] { e });
});
});
Using arootbeer's answer.
var grouped = items.GroupBy(i => i.Name);
grouped.ForEach(x => {
x.ForEach(e => {
// results handled here
((dynamic)e).Add((dynamic)e);
});
});

Inheriting a Linq to SQL class and cast the result of a linq query

I am writing an application where we will need to extend a basic entity into a number of different things (eg employee, vehicle etc). The design is as such that there is a Entity table and a second table with type specific values eg an employee will have an ID Number but a vehicle will have a registration number.
I have inherited from the class entity generated in the Data Context but am having trouble with the casting in my repository. What is the correct way of doing this?
public class cAccountEmployee : cAccountEntity
{
public string id_number
{
get
{
try
{
return this.cAccountEntityValues.Single(e => e.type == 1).value;
}
catch (Exception)
{
return "";
}
}
set
{
try
{
this.cAccountEntityValues.Single(e => e.type == 1).value = value;
}
catch (Exception)
{
this.cAccountEntityValues.Add(new cAccountEntityValue()
{
accountentity_id = this.id,
cAccountEntity = this,
type = 1,
value = value
});
}
}
}
}
Then in my repository (does not inherit anything)
public IEnumerable<cAccountEmployee> All(int accountholder_id)
{
return db.cAccountEntities.Where(e => e.accountholder_id == accountholder_id).OrderBy(a => a.name).Cast<cAccountEmployee>();
}
public cAccountEmployee Single(int id)
{
return db.cAccountEntities.Single(a => a.id == id) as cAccountEmployee;
}
The cast fails in the single method and hence I get back null. It is my understanding you cannot define explicit or implicit operators from or to a base class? How can I get the base class Linq result to cast up to the inherited Employee class, while still maintaining its db state so I can submit changes?
With LINQ-to-SQL, there are two ways inheritance can work:
discriminator over a single table (not suitable since your data is not homogeneous)
base-class / multi-table (not that this isn't supported in the dbml - only if you write the classes manually)
LINQ-to-SQL does not support multi-table inheritance (i.e. a single object with data from multiple tables). Entity Framework does, but is more complex; you use .Cast<T> and .OfType<T> in EF to cast/filter based on sub-types.
You might want to look at:
querying based on an ID (combine with GetTable<T>())
specifying a base-class in the dbml
What is the purpose of the base class here? If it adds behaviour, then you can edit the dbml to specify a common base-class for all your entities. If it has data properties then it gets trickier.
Personally, I simply wouldn't do it this way... I would keep separate classes for the different types, and use the data-context correctly, using the separate tables per type:
public IEnumerable<Employee> All(int accountholder_id)
{
return db.Employees.Where(e => e.accountholder_id == accountholder_id)
.OrderBy(a => a.name);
}
public Employee Single(int id)
{
return db.Employees.Single(a => a.id == id);
}
So - can you clarify what the cAccountEntity does here?
Thanks for the input, will look over some of the suggestions...
The idea behind account entity was that as of now the site only needs to handle employees but in the future they may want to add vehicles etc to the system, the system is used to assign costs to an entity, so for this purpose an employee is handled the same as a vehicle.
The idea being that an employee and a vehicle need to he handled the same for referencing in the db etc but will need slightly different info about them. It is a complex design only because they want to add extra types later but without needing to upgrade the db...
In my code however I want to talk about an employee not about a generic entity type (make controller, view etc much easier in an mvc app). As you cannot supply a user-defined casting from base to derived class I have skipped inheritting it and used the following solution instead. Bit more cumbersome but does work... Let me know if someone can see a better way of doing this.
public class cAccountEmployee
{
private cAccountEntity entity;
public int id
{
get
{
return this.entity.id;
}
set
{
this.entity.id = value;
}
}
public string name
{
get
{
return this.entity.name;
}
set
{
this.entity.name = value;
}
}
public int accountholder_id
{
get
{
return this.entity.accountholder_id;
}
set
{
this.entity.accountholder_id = value;
}
}
public System.Data.Linq.EntitySet<cAccountEntityValue> cAccountEntityValues
{
get
{
return this.entity.cAccountEntityValues;
}
}
public cAccountHolder cAccountHolder
{
get
{
return this.entity.cAccountHolder;
}
}
public cAccountEmployee()
{
this.entity = new cAccountEntity();
}
public cAccountEmployee(cAccountEntity entity)
{
this.entity = entity;
}
public string id_number
{
get
{
try
{
return this.entity.cAccountEntityValues.Single(e => e.type == 1).value;
}
catch (Exception)
{
return "";
}
}
set
{
try
{
this.entity.cAccountEntityValues.Single(e => e.type == 1).value = value;
}
catch (Exception)
{
this.entity.cAccountEntityValues.Add(new cAccountEntityValue()
{
accountentity_id = this.id,
cAccountEntity = this.entity,
type = 1,
value = value
});
}
}
}
}
//In the repository
public cAccountEmployee Single(int id)
{
return new cAccountEmployee(db.cAccountEntities.Single(a => a.id == id));
}
How can I get the base class Linq result to cast up to the inherited Employee class
It's not an upcast, it's a downcast.
I think you don't understand casting or possibly - instance type vs reference type.
public class Animal { }
public class Zebra : Animal { }
public class Zoo
{
public void ShowZebraCast()
{
Animal a = new Animal();
Zebra z = (Zebra)a;
}
}
System.InvalidCastException: Unable to cast object of type 'Animal' to type 'Zebra'.
In the same way, you have an instance of Entity that you can't downcast to use an Employee reference against it.
You could convert the types, but then you have to supply a conversion method.
public partial class Animal { }
public class Zebra : Animal { }
//in another file
public partial class Animal{
public Zebra ToZebra(){
return new Zebra() { //set Zebra properties here.
};
}
}
public class Zoo
{
public void ShowZebraConvert()
{
Animal a = new Animal();
Zebra z = a.ToZebra();
}
}

Categories