How to do generic polymorphism on open types in C#?
Since you don't want to force a specific type, make an abstract class
or an interface
this way:
interface IFoo { }
And inherit it in your type-specific Foo (with generic parameters), like:
interface IFoo<T> : IFoo {}
This way you can just have a List<IFoo>
and add IFoo<T>
instead.
More examples:
class FooCollection {
private List<IFoo> _collection;
public FooCollection()
{
_collection = new List<IFoo>();
}
public void Add(IFoo foo)
{
_collection.Add(foo);
}
public void Remove(IFoo foo)
{
_collection.Remove(foo);
}
}
Polymorphism in C# generic types
You can't define class Concrete<int>
with <int>
- it's like you're trying to override the normal definition of int
with a new generic type called int
. But then in the class you're trying to actually return an int
.
So it should look like:
class Concrete : IOpen<int>
{
public int A => 42;
public string B => "42";
}
But now the class WorkerInt
would have to look like this:
class WorkerInt : IWorker<int>
{
public void Do(Concrete item)
{
Console.WriteLine(item.A);
Console.WriteLine(item.B);
}
}
But IWorker<int>
must implement void Do(IOpen<T> item)
and even though Concrete
implements IOpen<T>
you can't use void Do(Concrete item)
because it is more restrictive than void Do(IOpen<T> item)
.
So you must define it this way:
class WorkerInt : IWorker<int>
{
public void Do(IOpen<int> item)
{
Console.WriteLine(item.A);
//Console.WriteLine(item.B);
}
}
But that makes item.B
no longer work as IOpen<int>
doesn't have a B
property.
The only way to make this work is to change IWorker
to be this:
interface IWorker<T, R> where T : IOpen<R>
{
void Do(T item);
}
Then WorkerInt
can be this:
class WorkerInt : IWorker<Concrete, int>
{
public void Do(Concrete item)
{
Console.WriteLine(item.A);
Console.WriteLine(item.B);
}
}
Realizing polymorphism with Generics in C#
It is possible to achieve this with generics as such:
First, you want to create Generic classes for your parser and repository:
public class Parser<T> : IParser<T>
{
IList<T> ParseDataTableToList(DataTable dataTable, object o)
{
var list = new List<T>();
//Your parsing logic can go:
//1) Here(using reflection, for example) or
//2) in the constructor for Motor/Switchboard object,
//in witch case they will take a reader or row object
return list;
}
}
public class Repo<T> : IInsertOrUpdateList<T>
{
void InsertOrUpdate(IList<T> list)
{
//...
}
}
And then, your Generic window class looks like this:
public partial class ImportView<T> : Form
{
private IParser<T> parser;
private IInsertOrUpdateList<T> repository;
private DataTable dataToParse;
public ImportView(DataTable dataToParse)
{
this.parser = new Parser<T>();
this.repository = new Repo<T>();
this.dataToParse = dataToParse;
}
public void ParseAndInsertIntoDB()
{
repository.InsertOrUpdate(parser.ParseDataTableToList(dataToParse, null));
}
}
And you instantiate it like this:
var ImportView = new ImportView<Motor>(YourDataTable)
How to create List of open generic type of classT?
There is no diamond operator in C# yet, so you can't use true polymorphism on open generic type underlying to closed constructed types.
So you can't create a list like this:
List<Data<>> list = new List<Data<>>();
You can't use polymorphism on such list... and it is a lack in genericity here.
For example, in C# you can't create a List<Washer<>>
instance to have some Washer<Cat>
and some Washer<Dog>
to operate Wash()
on them...
All you can do is using a list of objects or an ugly non generic interface pattern:
public interface IData
{
void SomeMethod();
}
public abstract class Data<T> : IData
{
public void SomeMethod()
{
}
}
List<IData> list = new List<IData>();
foreach (var item in list)
item.SomeMethod();
You can also use a non generic abstract class instead of an interface:
public abstract class DataBase
{
public abstract void SomeMethod();
}
public abstract class Data<T> : DataBase
{
public override void SomeMethod()
{
}
}
List<DataBase> list = new List<DataBase>();
foreach (var item in list)
item.SomeMethod();
But you lost some genericity design and strong-typing...
And you may provide any non-generic behavior such as properties and methods you need to operate on.
Generics open and closed constructed types
C# variance problem: Assigning List<Derived> as List<Base>
How to do generic polymorphism on open types in C#?
C# : Is Variance (Covariance / Contravariance) another word for Polymorphism?
C# generic inheritance and covariance part 2
still confused about covariance and contravariance & in/out
Covariance and Contravariance (C#)
Covariance & Contravariance
Generic Classes (C# Programming Guide)
Polymorphism by generic types where types do not share a base class
If the entities do not have the same base class, the best you can do is to have a class constraint.
Since both expressions are essentially the same, you should just pass one expression and a function to get the key value from the entity.
The Count
and First
methods can also be merged into a single statement and then checking for null
.
int? MethodToRefactor<T>(DbSet<T> entities, Func<string, Expression<Func<T, bool>>> expressionFilter, Func<T, int> getIdFunc, IList<string> someCollection, string[] moreParams)
where T : class
{
int? keyValue = null;
foreach (var itemDetail in someCollection)
{
string refText = GetRefTextBySource(itemDetail, moreParams);
var entity = entities.FirstOrDefault(expressionFilter(refText));
if (entity != null)
{
keyValue = getIdFunc(entity);
}
if (...some conditional code...)
break;
}
return keyValue;
}
You would call the method like this
id = MethodToRefactor<Account>(db.Accounts, txt => a => a.Name == txt, a => a.AccountId, ...);
id = MethodToRefactor<Customer>(db.Customers, txt => c => c.CustomerName == txt, c => c.CustomerId, ...);
C# Generics and polymorphism: an oxymoron?
As far as I can see, consuming code doesn't need specifics of generic class (i.e., it doesn't depends on what T
is). So, why don't you introduce interface that SomeClass<T>
will implement, and use instance of this interface.
E.g.:
public interface ISome
{
void SomeMethod();
}
public class SomeClass<T>: ISome
{
public virtual void SomeMethod(){ }
}
public void DoSomethingClienty()
{
Factory factory = new Factory();
ISome someInstance = factory.Create();
someInstance.SomeMethod();
}
Now, subclasses of SomeClass<T>
can operate differently on different T
s, but consuming code won't change.
How to use an object of a generic class inside a generic class in C#?
It's actually impossible because not supported by the compiler else it would cause a stack overflow of the compiler with such thing that is endless and so impossible, because of the generic type verification as currently defined by the .NET specifications that are more strict than templates in C++.
You could use a LinkedList<ChainedItem<>>
but the diamond operator hence true generic polymorphism are not available in C#:
How to do generic polymorphism on open types in C#?
Therefore perhaps you can write such thing using an interface and type checking, excluding null values:
public interface IChainedItem
{
void DoOperation(object value);
}
public abstract class ChainedItem<T> : IChainedItem
{
private IChainedItem m_chainedItem;
public void SetNextChainedItem(IChainedItem chainedItem)
{
m_chainedItem = chainedItem;
}
public abstract void DoOperation(T data);
public virtual void ContinueNextOperation(object data)
{
if ( m_chainedItem != null )
m_chainedItem.DoOperation(data);
}
public void DoOperation(object value)
{
if ( value == null )
throw new ArgumentNullException();
var typeIn = value.GetType();
var typeRequired = typeof(T);
if ( typeIn != typeRequired )
{
string message = $"Bad type in ChainedItem.DoOperation(object): "
+ $"{typeRequired.Name} is required and not {typeIn.Name}.";
throw new ArgumentException(message);
}
DoOperation((T)value);
}
}
Type.GetMethod() for polymorphic method (both generic and non-generic)
In .NET 4.7.1 you need to use method GetMethods
and filter the results:
class MyClass
{
public T M<T>(T t) { return default(T); }
public int M(int t) { return 0; }
}
var m = typeof(MyClass).GetMethod("M", new[] { typeof(string) }); // null
var m1 = typeof(MyClass).GetMethods()
.Where(mi => mi.Name == "M" && mi.GetGenericArguments().Any())
.First(); // returns generic method
In .NET Standard 2.1 (and .NET Core since 2.1) there is another way to resolve generic type arguments - Type.MakeGenericMethodParameter
, like you can see it in this answer.
Also as workaround you can move your copyAutofields<T>
method to generic class like CopyAutoFieldServer<T>
:
public static class CopyAutoFieldServer<T>
{
public static T copyAutofields(T original) { ... }
}
How to define an aggregated ICollectionT where T is type of the current declaring class within a hierarchy?
No, there is no way to do such thing yet.
The C# language has no artifact to declare such thing:
class A
{
public ICollection<T> Children where T : thisdeclaring;
}Where
thisdeclaring
represents the current declaring type.C# does not support true polymorphism on open types using the diamond operator
<>
How to create List of open generic type of class?
How to do generic polymorphism on open types in C#?
Solution 1 : type checking hack on the non generic type
We check the type at runtime to throw an exeption in case of mismatch, but we must lost the genericity as explained in previous links:
using System.Reflexion;
class A
{
private ICollection _Children;
public ICollection Children
{
get => _Children;
set
{
if ( value == null )
{
_Children = null;
return;
}
var genargs = value.GetType().GenericTypeArguments;
if (genargs.Length != 1 || this.GetType() != genargs[0] )
{
string msg = $"Type of new {nameof(Children)} items must be {this.GetType().Name}: "
+ $"{ genargs[0].Name} provided.";
throw new TypeAccessException(msg);
}
_Children = value;
}
}
}
Test
var a = new A();
trycatch(() => a.Children = new List<A>());
trycatch(() => a.Children = new List<B>());
Console.WriteLine();
var b = new B();
trycatch(() => b.Children = new List<A>());
trycatch(() => b.Children = new List<B>());
void trycatch(Action action)
{
try
{
action();
Console.WriteLine("ok");
}
catch ( Exception ex )
{
Console.WriteLine(ex.Message);
}
}
Output
ok
Type of new Children items must be A: B provided.
Type of new Children items must be B: A provided.
ok
So we can't have the generic type parameter on the collection and the hierarchical type contrainst at the same time, as I know, for the moment.
Solution 2 : the same hack using dynamic to keep genericity
private dynamic _Children;
public dynamic Children
set
{
if ( value == null )
{
_Children = null;
return;
}
bool isValid = false;
foreach ( Type type in value.GetType().GetInterfaces() )
if ( type.IsGenericType )
if ( type.GetGenericTypeDefinition() == typeof(ICollection<>) )
{
isValid = true;
break;
}
if ( !isValid )
{
string msg = $"{nameof(Children)} must be a ICollection of {this.GetType().Name}: "
+ $"{value.GetType().Name} provided.";
throw new TypeAccessException(msg);
}
var genargs = value.GetType().GenericTypeArguments;
if ( genargs.Length != 1 || this.GetType() != genargs[0] )
{
string msg = $"Type of new {nameof(Children)} items must be {this.GetType().Name}: "
+ $"{ genargs[0].Name} provided.";
throw new TypeAccessException(msg);
}
_Children = value;
}
}
Here we keep the generic closed constructed type of the collection.
Thus we can use all generic members of the stored instance.
Related Topics
Why Enums Require an Explicit Cast to Int Type
What's the Equivalent of Vb's Asc() and Chr() Functions in C#
How to Urlencode Without Using System.Web
Generating Xml File Using Xsd File
Embed Unity3D App Inside Wpf Application
What Is the Correct Way to Read a Serial Port Using .Net Framework
How to Programmatically Set Cell Value in Datagridview
Copy Object to Object (With Automapper )
Is Nameof() Evaluated at Compile-Time
Serialize Property, But Do Not Deserialize Property in JSON.Net
Datetime.Tryparse Century Control C#
How to Fix Error: "Could Not Find Schema Information for the Attribute/Element" by Creating Schema
Multiple File-Extensions Searchpattern for System.Io.Directory.Getfiles
How to Check Whether an Object Has Certain Method/Property
I Need a Fast Runtime Expression Parser
How to Generate a Cryptographically Secure Pseudorandom Number in C#