create generic method for abstract inherited class without interface - c#

I'm not sure if this question has come up before but I certainly haven't found an answer to it yet so here I am asking the community.
I have a third party library that has an abstract class (lets say A) which implements IXinterface
public abstract class A : IXinterface{
}
This class is then derived by a number of child classes, Each one of these classes have properties such Product
public class B : A {
public Product Product {get; set; }
}
public class C : A {
public Product Product {get; set; }
}
my issue is this.
I would like to create a generic method that such as this:
public List<PriceModel> GetPriceModelList(List<PriceModel> priceModelList, List<T> resultsList) where T : class
{
priceModelList.AddRange(from result in resultsList
from item in result.Product.Price
select new PriceModel
{
Price = item.price
});
return priceModelList;
}
I want to be able to do something like this
GetPriceModelList(new List<PriceModel>(), new List<B>());
GetPriceModelList(new List<PriceModel>(), new List<C>());
OR
change method signiture to accept T
GetPriceModelList<B>(new List<PriceModel>(), resultsList);
GetPriceModelList<C>(new List<PriceModel>(), resultsList);
obviously because I do not have a common concrete class or interface I can not explicitly state the type T and the abstract class does not have accessor methods to the derived classes properties. Therefore when result is fetched from the List of type T Product is not available.
Is there a way around this issue

You could cut out the intermediary, and directly operate on sequences of products.
public List<PriceModel> GetPriceModelList(
List<PriceModel> priceModelList,
IEnumerable<Product> products)
{
priceModelList.AddRange(from result in products
from item in result.Product.Price
select new PriceModel
{
Price = item.price
});
return priceModelList;
}
That would mean you'd have to provide the mechanism for getting each product at the call site.
GetPriceModelList(new List<PriceModel>(), new List<B>().Select(b => b.Product));
GetPriceModelList(new List<PriceModel>(), new List<C>().Select(c => c.Product));

Can you explain the from item in result.Product.Price line?
For me it looks like you just want:
priceModelList.AddRange(from result in resultsList
select new PriceModel
{
Price = result.Product.Price
});
To do that, you can just replace it with:
priceModelList.AddRange(from result in new List<dynamic>(resultsList)
select new PriceModel
{
Price = result.Product.Price
});
Then you can even call it in this way:
GetPriceModelList(new List<PriceModel>(),
new List<A>
{
new B { Product = new Product() },
new C { Product = new Product() }
});
But it is also a good idea to guard yourself by checking if T is actually of type B or C.

Related

Find a derived class in a list of its base class

So I have a List of BaseClass and I've filled it with several instances of derived classes (only one of each derived class) so that we have something like:
List<BaseClass> myList = new List<BaseClass>();
myList.Add(new DerivedClassA());
myList.Add(new DerivedClassB());
myList.Add(new DerivedClassC());
Now I want to be able to search myList with something like this:
public void FindClass (BaseClass class){ //class is a derived class
//find index or object of type class
//so that if class is a DerivedClassB
//we return the first DerivedClassB in myList
}
Is this possible? I know I can give each DerivedClass a name property and find it by it's name but I don't want to have to do that.
Another solution would be to use 'OfType<>' to filter the list
public class Base { }
public class DerivedA : Base { }
public class DerivedB : Base { }
List<Base> instances = new List<Base>();
instances.Add(new DerivedA());
instances.Add(new DerivedB());
var results = instances.OfType<DerivedA>().FirstOrDefault();
EDIT - This is a way of creating a method that would do the search
T Find<T>() where T : Base {
return _Instances.OfType<T>().FirstOrDefault();
}
If you pass in an instance of DerivedClassB, you can find all instances of DerivedClassB by comparing the actual type of the instance passed in and of the instances in the list:
public IEnumerable<BaseClass> FindClass (BaseClass #class){
return myList.Where(c => c.GetType() == #class.GetType());
}
You can do this with the is operator. It tells you if an object is of a given type. Add a little LINQ and you get:
var firstB = myList
.Where(c => c is DerivedClassB)
.First();

Creating common class objects based on class name and use it

I have the same code logic used across different class objects.
For ex:
var matchingTypes = from matchType in order.Contacts
select matchType;
var matchingTypes = from matchType in customer.Contacts
select matchType;
Instead of writing duplicate lines of code, i would like to pass order, customer class names and get Contacts through it, so that the above code will look like (we are using LINQ in our code)
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
The stuff i tried is passed an object parameter
GetData(object objectElement) // method consuming an object parameter.
var objectOrder= objectElement as Orders;
var objectCustomer= objectElement as Customers;
if(objectOrder!=null)
{
objectElement = (Orders) objectOrder; //type
}
if(objectCustomer !=null)
{
objectElement = (Customers) objectCustomer;
}
By doing so, i am repeating my code, which i would like to avoid, any suggestions/ideas? thanks.
I would like to use objectElement and assign only once, so that i can call like this as shown below
var matchingTypes = from matchType in objectElement.Contacts
select matchType;
An interface would be the preferred way to do this, but you could also use dynamic to duck type a method:
public IEnumerable<Contact> GetContacts(dynamic yourObject)
{
return yourObject.Contacts;
}
Note this will not give you a compile error if you call it with something that doesn't have a property called Contacts of type IEnumerable<Contact> but will instead give you a runtime error.
Or you don't even actually need a method, you could just do this:
var matchedTypes = ((dynamic)yourObject).Contacts as IEnumerable<Contact>;
Interfaces would be a safer bet, but are a little tricky with generate entity framework classes. But you can do them becuase they are generated as partial classes. So you can do something like this:
public interface IHaveContacts
{
public IEnumerable<Contact> Contacts { get; }
}
and then:
public partial class Orders : IHaveContacts
{
// should need to do anything since the auto-genrated Contacts property
// will satisfy the interface
}
public partial class Customers : IHaveContacts
{
// ditto
}
And now you can do:
var matchedTypes = ((IHaveContacts)yourObject).Contacts;
Or, if you really, really must (which you don't):
var matchedTypes = from matchType in ((IHaveContacts)yourObject).Contacts
select matchType;
Create an interface IContactsContainer:
public interface IContactsContainer
{
public YourContactType Contacts{get;set;}
}
Then your customer and order classes can implement it:
public class Customers : IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
public class Orders: IContactsContainer
{
public YourContactType Contacts {get;set;}
....
}
After that in your method you can use:
IContactsContainer objectElement = yourOrderObject;

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...()

Create a list of objects and display them in the console through another class

For a homework assignment i need to create a List<T>, add objects to it, and display the objects toString. Here is what i have:
public class Order
{
...
public List<OrderLine> orderLines;
public Order(User user1)
{
...
orderLines = new List<OrderLine>();
}
public void AddOrderLine(OrderLine newOrderLine)
{
orderLines.Add(newOrderLine);
}
}
public class OrderLine
{
public OrderLine(Product p1, int q1)
{
...
}
public override string ToString() //Required by teacher
{
string myOrderLine;
myOrderLine = String.Format("[Product name: {0}; Price: {1}; Quantity: {2}]",
product.name, product.price, quantity);
return myOrderLine;
}
}
When adding oerderLines.Add(newOrderLine) new OrderLine is an object created in another class that has a working toString. How do i display all the newOrderLines from the Program.CS?
I assume your main method looks something like this:
{
User user = new User();
Order order = new Order(user);
OrderLine orderLine1 = new OrderLine();
order.AddOrderLine(orderLine1);
}
If I understand what you say correctly, OrderLine already overrides ToString(), so that when you call ToString(), it returns something "human-meaningful". In that case, the only thing you need to do is something along the lines of
foreach (var orderLine in order.orderLines)
{
Console.WriteLine(orderLine.ToString());
}
Note that it is considered good practice not to publicly expose a field, like orderLines. Better make it private, and create a public property like:
public IEnumerable<OrderLine> OrderLines
{
get { return this.orderLines; }
}
Assuming you have the working .ToString() for the OrderLine class. If you just want to display them to the console, you can do a simple:
foreach(OrderLine orderline in orderLines)
System.Console.WriteLine(orderline.ToString());
edit:
Two simple ways to do this is either the way Mathias outlined quite nicely or put my code inside your Order class. For example, add a new method like this:
public void PrintOrders()
{
foreach(OrderLine orderline in this.orderLines)
System.Console.WriteLine(orderline.ToString());
}
You would use it like:
User user = new User();
Order order = new Order(user);
OrderLine orderLine = new OrderLine();
order.AddOrderLine(orderLine);
order.PrintOrders();
Please note that it is generally not considered good practice to have classes printing to the console. I just wanted to show you a different way of approaching the problem.
if you have something like this in your Program.cs to populate your Order object
var order = new Order();
order.AddOrderLine(...);
//this is how you can display each item ToString in the collection
foreach(var o in order.orderLines)
{
Console.WriteLine(o.ToString());
}
just check for any typo or syntax error as I only typed this here inline
Is this what you need?
public static void Main(string[] args)
{
Order order = new Order();
OrderLine line1 = new OrderLine(...);
OrderLine line2 = new OrderLine(...);
OrderLine line3 = new OrderLine(...);
order.AddOrderLine(line1);
order.AddOrderLine(line2);
order.AddOrderLine(line3);
foreach (OrderLine line in order.orderLines)
{
Console.WriteLine(line.ToString());
}
}

how do i refactor this code?

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.

Categories