C# generic method that takes multiple classes - c#

I want to create a generic method like this one:
public static List<T> Filter(this List<T> list, string search) where T : class
{
return list.Where(t => t.Name.FormatSearch().Contains(search)).ToList();
}
And to be albe to call this method on different classes and get the same result because both classes have mostly the same attributes.
class A {
public string Name;
}
class B {
public string Name;
}
var a = new List<A>();
var b = new List<B>();
a.Filter();
b.Filter();
I expect the filter method to work the same way for both A and B. What Am I'm missing in the first method?

One way to do that is to create Interface IName and declare Name Property there.
A and B should implement IName.
Write T parameter constraint as follows where T : IName
After that you will avoid red line under t.Name...
Try following .
using System.Collections.Generic;
using System.Linq;
namespace TestField
{
class Program
{
private static void Main(string[] args)
{
var a = new List<A>();
var b = new List<B>();
a.Filter("string");
b.Filter("string");
}
}
public static class Extensions
{
public static List<T> Filter<T>(this IEnumerable<T> list, string search)
where T : IName
=> list.Where(t => t.Name.Contains(search)).ToList();
}
public interface IName
{
string Name { get; set; }
}
public class A : IName
{
public string Name { get; set; }
}
public class B : IName
{
public string Name { get; set; }
}
}

The answer was given by #tchelidze this is what I wanted to do:
public interface IName
{
string Name { set; get; }
}
class A : IName {
public string Name
}
class B : IName {
public string Name
}
public static List<T> Filter<T>(this List<T> list, string search) where T : IName
{
return list.Where(t => t.Name.FormatSearch().Contains(search)).ToList();
}

Related

Get a Static property from a class generic, where Interface contains the property name

When you have a function:
public interface IHasName
{
static string Name { get; }
}
//class{
public static string GetName<T>() where T : IHasName
{
return T.Name;
}
//}
This is not working, only when I change the static to public and I create a new T().
The usage have to be like:
public class Model: IHasName
{
public static string Name => "Niek";
}
var name = GetName<Model>();
Do you have the solution that sill use a static property through a Generic.
Thanks in advance!
This is available as a preview feature in .NET 6, and will probably be properly released in .NET 7:
public interface IHasName
{
public static abstract string Name { get; }
}
public class Model : IHasName
{
public static string Name => "Foo";
}
class Foo
{
public static string GetName<T>() where T : IHasName
{
return T.Name;
}
}
See it on dotnetfiddle.net.

Creating one helper method for different types via interface c#

I have a requirement to order several lists by the same value. But, for whatever reason, these lists contain objects of different types which share this value. Let's call it ChildID.
The simplified model code would look something like this:
public class Child
{
public string ChildID { get; set; }
}
public class Parent
{
public Child Child { get; set; }
}
public class OtherClassID
{
public int ID { get; set; }
public string ChildID { get; set; }
}
public class SomeOtherClass
{
public OtherClassID ID { get; set; }
}
So, in order to avoid code duplication, I tried this:
public interface IHasChildID
{
string GetChildID();
}
public class Child : IHasChildID
{
public string ChildID { get; set; }
public string GetChildID()
{
return ChildID;
}
}
public class Parent : IHasChildID
{
public Child Child { get; set; }
public string GetChildID()
{
return Child.ChildID;
}
}
public class OtherClassID
{
public int ID { get; set; }
public string ChildID { get; set; }
}
public class SomeOtherClass : IHasChildID
{
public OtherClassID ID { get; set; }
public string GetChildID()
{
return ID.ChildID;
}
}
And when I created a helper class with a helper method which takes an interface as a parameter, I expected it to work:
public static class ChildOrderHelper
{
public static IEnumerable<IHasChildID> OrderChildren(IEnumerable<IHasChildID> children)
{
var childrenList = children.ToList();
//do some splitting, ordering and conatenation of lists
return orderedList;
}
}
But, on every helper call I get an error:
List<Child> originalList = GetChildren(); // whatever
// some lines of code
var orderedList = ChildOrderHelper.OrderChildren(originalList).ToList(); // error
Error CS1503 Argument 1: cannot convert from
'System.Collections.Generic.List<NamespaceOne.Child>' to
'System.Collections.Generic.List<NamespaceTwo.IHasChildID>'
And so for every helper call, no matter the type.
One thing to note is that I've given an example with three distinct types that have this value and need to be ordered by it. In the project, there is probably 10 or more.
I guess there is something fundamental I don't yet understand about interface usage, but any help would be appreciated on this matter.
I'm not entirely sure what your overall use case is, but maybe it would be beneficial to make the OrderChildren method generic, as follows:
public static class ChildOrderHelper
{
public static IEnumerable<T> OrderChildren<T>(IEnumerable<T> children) where T : IHasChildID
{
var childrenList = children.ToList();
//just a simple example of what I'm guessing the method could do...
return childrenList.OrderBy(c => c.GetChildID()).ToList();
}
}
And call it as follows:
List<Child> originalList = GetChildren();
List<Child> orderedList = ChildOrderHelper.OrderChildren<Child>(originalList).ToList();
The approach can be taken like defining an interface and then implemenint that one in all the required classes or a base class that can lookup the child id.
Below is a sample of the source code.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections;
public class Program
{
public static void Main()
{
var parents = new List<Parent>();
parents.Add(new Parent{ChildId = "123"});
parents.Add(new Parent{ChildId = "321"});
parents.Add(new Parent{ChildId = "456"});
var result = ChildHelpers.OrderChildren(parents);
foreach(var res in result) {
Console.WriteLine(res.ChildId);
}
Console.WriteLine("Hello World");
}
}
public interface IChild {
string ChildId {get;set;}
}
public class Child : IChild {
public string Name {get;set;}
public string ChildId {get;set;}
}
public class Parent : IChild {
public Parent() {
child = new Child();
}
public Child child {get;set;}
public string ChildId {
get{
return child.ChildId;
}
set{
child.ChildId = value;
}
}
}
public class AnotherChild : IChild {
public string Description{get;set;}
public string ChildId {get;set;}
}
public static class ChildHelpers {
public static IEnumerable<IChild> OrderChildren(IEnumerable<IChild> children)
{
return children.OrderBy(c=>c.ChildId).AsEnumerable();
}
}
If you would like to playaround with this sample and see other options if required, please refer this link.

Generic Methods, how to call a parent method without specifying a type

I have this parent class
public abstract class Parent
{
public string Id { get; set; }
public static T Find<T>(string id) where T : class, new()
{
/* logic here ..*/
}
}
and this child
public class Child : Parent
{
public string Name { get; set; }
}
Right now, the Find() method can be called from child class like this Child.Find<Child>(myId);
What I need to change so it doesnt have to include class type like this Child.Find(myId);
EDIT
I want to make this method as extension, and get it directly without defining the class into variable. the generic classT should be it's child type.
One option would be to add this method to your Child class:
public static Child Find(string id)
{
return Parent.Find<Child>(id);
}
I would do something like this:
public abstract class Parent<T> where T : class, new()
{
public T Find(string id)
{
return new T();
}
}
public class Child : Parent<Child>
{
public void Test()
{
var child = base.Find ("");
}
}
Do you mean something like this:
public abstract class Parent
{
public string Id { get; set; }
public static Parent Find(string id)
{
/* logic here ..*/
}
}
This way you would have to cast the output to the correct type of derived class. For example:
if(Parent.Find("123") is Child child)
{
child.Name = "TEST";
}
EDIT
Hide the inherited member and define a new one:
public abstract class Parent
{
public string Id { get; set; }
public static Parent Find(string id)
{
/* logic here ..*/
}
}
public class Child : Parent
{
public string Name { get; set; }
public new static Child Find(string id)
{
/* logic here */
}
}
This would be the extension method approach:
public static class ExtensionMethods
{
public static T Find<T>(this T source, string id) where T : class, new()
{
return new T();
}
}
public class Child
{
public void FindChild()
{
this.Find("");
}
}

Extending classes with additional properties

I have an class object from an external library that I want to add some additional properties to.
Let's say the external class is:
public class ExternalClass
{
public string EXproperty1 {get;set;}
public string EXproperty2 {get;set;}
public string EXproperty3 {get;set;}
public ExternalClass(){}
}
and I have a list of these object which gets populated as
List<ExternalClass> listOfExternalClass=new List<ExternalClass>();
listOfExternalClass=GetListOfExternalClass();
I can extend this class by creating a new class, adding the additional properties and making the external class a property.
public class NewClass
{
public ExternalClass ExternalClass {get;set;}
public string NewProperty1 {get;set;}
public string NewProperty2 {get;set;}
public NewClass(){}
public NewClass(ExternalClass externalClass){
this.ExternalClass=externalClass;
}
}
But to convert by original list of the external classes to a list of the new classes I would have to create a new list of new classes and iterate through the original list creating a new object and adding it to the list, like
List<NewClass> listOfNewClass=new List<NewClass>();
foreach(var externalClass in listOfExternalClass)
{
listOfNewClass.Add(new NewClass(externalClass));
}
I would then be able to access the external properties like
listOfNewClass.FirstOrDefault().ExternalClass.EXproperty1;
Can I do this with inheritance or is there a more efficient method?
Ideally I would like to end up with by calling the properties like:
listOfNewClass.FirstOrDefault().EXproperty1;
This can certainly be done with inheritance. Consider the following.
//Inherit from our external class
public class NewClass: ExternalClass
{
//Note we do not have a copy of an ExternalClass object here.
//This class itself will now have all of its instance members.
public string NewProperty1 {get;set;}
public string NewProperty2 {get;set;}
//If it has parameters include those parameters in NewClass() and add them to base().
//This is important so we don't have to write all the properties ourself.
//In some cases it's even impossible to write to those properties making this approach mandatory.
public NewClass()
{
}
}
Few things to know:
Your code is called a wrapper. This is because it "wraps" another class or group of classes.
You cannot inherit from class marked as sealed.
In C# classes are not sealed by default. If they're sealed the developer has intentionally prevented you from inheriting from the class. This is usually for a good reason.
If you can actually extend the External class that would be easy to accomplish:
public class NewClass: ExternalClass
{
public string NewProperty1 {get;set;}
public string NewProperty2 {get;set;}
public NewClass(){}
public NewClass(ExternalClass externalClass){
// you would have to copy all the properties
this.EXproperty1 = externalClass.EXproperty1;
}
}
Yes inheritance is what you are looking for:
public class ExternalClass
{
public string EXproperty1 { get; set; }
public string EXproperty2 { get; set; }
public string EXproperty3 { get; set; }
public ExternalClass() { }
}
public class NewClass:ExternalClass
{
public string NewProperty1 { get; set; }
public string NewProperty2 { get; set; }
public NewClass() { }
}
If you wish for (or need) delegation instead of a copy you can do:
public class NewClass
{
public ExternalClass ExternalClass {get;set;}
public string NewProperty1 {get;set;}
public string NewProperty2 {get;set;}
public string EXproperty1 {get { return this.ExternalClass.EXproperty1; };set{ this.ExternalClass.EXproperty1 = value; }; }
public string EXproperty2 {get { return this.ExternalClass.EXproperty2; };set{ this.ExternalClass.EXproperty2 = value; }; }
public string EXproperty3 {get { return this.ExternalClass.EXproperty3; };set{ this.ExternalClass.EXproperty3 = value; }; }
public NewClass(){}
public NewClass(ExternalClass externalClass){
this.ExternalClass=externalClass;
}
}
Instead of working against specific types, work against interfaces.
Below I am showing a mix of facade pattern and adapter pattern to 'transform' external data to a well-defined interface (IDocument), effectively abstracting things your are working on.
Example 1 : query about an interface
Here are the types you'll work against:
public interface IDocument {
string Name { get; set; }
}
public interface IMetadata {
string[] Tags { get; set; }
}
This is your own representation, should you need any:
public class RichDocument : IDocument, IMetadata {
public string Name { get; set; }
public string[] Tags { get; set; }
}
This is the wrapper against external data:
(a bastard mix of facade and/or adapter concepts)
public class ExternalClass {
public string Whatever { get; set; }
}
public class ExternalDocument : IDocument /* only a basic object */ {
private readonly ExternalClass _class;
public ExternalDocument(ExternalClass #class) {
_class = #class;
}
public string Name {
get { return _class.Whatever; }
set { _class.Whatever = value; }
}
}
And a demo on how to use all that:
internal class Demo1 {
public Demo1() {
var documents = new List<IDocument> {
new ExternalDocument(new ExternalClass()),
new RichDocument()
};
foreach (var document in documents){
var name = document.Name;
Console.WriteLine(name);
// see if it implements some interface and do something with it
var metadata = document as IMetadata;
if (metadata != null) {
Console.WriteLine(metadata.Tags);
}
}
}
}
Example 2 : query about a component
This is a bit more involved by pushing the concept to treat everything in an uniform manner, you can find it in .NET framework, game development or whatever ...
Definitions you'll work against:
public interface IContainer {
IList<IComponent> Components { get; }
}
public interface IComponent {
// it can be/do anything
}
Some components you'll query about:
public interface IDocument : IComponent {
string Name { get; set; }
}
public interface IMetadata : IComponent {
string[] Tags { get; set; }
}
Your 'internal' type:
public class Container : IContainer {
public Container() {
Components = new List<IComponent>();
}
public IList<IComponent> Components { get; }
}
Your 'wrapper' against external data:
public class ExternalClass {
public string Whatever { get; set; }
}
public class ExternalContainer : IContainer {
private readonly List<IComponent> _components;
public ExternalContainer(ExternalClass #class) {
_components = new List<IComponent> {new ExternalDocument(#class)};
}
public IList<IComponent> Components {
get { return _components; }
}
}
public class ExternalDocument : IDocument {
private readonly ExternalClass _class;
public ExternalDocument(ExternalClass #class) {
_class = #class;
}
public string Name {
get { return _class.Whatever; }
set { _class.Whatever = value; }
}
}
And a usage example:
public class Demo2 {
public Demo2() {
var containers = new List<IContainer> {
new ExternalContainer(new ExternalClass()),
new Container()
};
foreach (var container in containers) {
// query container for some components
var components = container.Components;
var document = components.OfType<IDocument>().FirstOrDefault();
if (document != null) {
Console.WriteLine(document.Name);
}
var metadata = components.OfType<IMetadata>().FirstOrDefault();
if (metadata != null) {
Console.WriteLine(metadata.Tags);
}
}
}
}
Notes
The problem with inheritance is that it is a very rigid approach and generally once you start doing it and at some point you hit a wall and want to revert, it's hard to get out of it.
By working against abstractions things are more flexible and things are decoupled.
Here are two examples that might incite you to change your approach:
Composition over inheritance
Using Components

How can I instantitate a list based on the specific object type?

I have the following definitions:
public class BaseEntity
{
...
public BaseEntity()
{
}
}
public class KeyValuePair
{
public string key;
public string value;
public string meta;
}
public class KeyValuePairList : BaseEntity
{
public List<KeyValuePair> List {set; get;}
public KeyValuePairList(IEnumerable<KeyValuePair> list)
{
this.List = new List<KeyValuePair>();
foreach (KeyValuePair k in list) {
this.List.Add(k);
}
}
}
I have 10 more different classes like KeyValuePair and KeyValuePairList all achieving the same purpose - the former defines the object, the latter defines the list into which these objects should be placed. How can I incorporate this functionality into the base class BaseEntity so that I don't have to redefine the List instantiation logic in each individual class i.e. I want to be able to instantiate the list based on the object type being passed to the constructor? Any suggestions?
Can you use generics?
public class BaseEntity<T> where T: class
{
public List<T> List { set; get; }
public BaseEntity(IEnumerable<T> list)
{
this.List = new List<T>();
foreach (T k in list)
{
this.List.Add(k);
}
}
}
public class KeyValuePair
{
public string key;
public string value;
public string meta;
}
public class KeyValuePairList : BaseEntity<KeyValuePair>
{
public KeyValuePairList(IEnumerable<KeyValuePair> list)
: base(list) { }
}

Categories