Wildcard equivalent in C# generics - c#

Let's say I have a generic class as follows:
public class GeneralPropertyMap<T>
{
}
In some other class I have a method that takes in an array of GeneralPropertyMap<T>. In Java, in order to take in an array that contains any type of GeneralPropertyMap the method would look like this:
private void TakeGeneralPropertyMap(GeneralPropertyMap<?>[] maps)
{
}
We use the wildcard so that later we can call TakeGeneralPropertyMap passing a bunch of GeneralPropertyMap with any type for T each, like this:
GeneralPropertyMap<?>[] maps = new GeneralPropertyMap<?>[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
//And finally pass the array in.
TakeGeneralPropertyMap(maps);
I'm trying to figure out an equivalent in C# with no success. Any ideas?

Generics in C# make stronger guarantees than generics in Java. Therefore, to do what you want in C#, you have to let the GeneralPropertyMap<T> class inherit from a non-generic version of that class (or interface).
public class GeneralPropertyMap<T> : GeneralPropertyMap
{
}
public class GeneralPropertyMap
{
// Only you can implement it:
internal GeneralPropertyMap() { }
}
Now you can do:
private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps)
{
}
And:
GeneralPropertyMap[] maps = new GeneralPropertyMap[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
TakeGeneralPropertyMap(maps);

While, as others have noted, there's no exact correspondence to wildcards in c#, some of their use cases can be covered with covariance/contravariance.
public interface IGeneralPropertyMap<out T> {} // a class can't be covariant, so
// we need to introduce an interface...
public class GeneralPropertyMap<T> : IGeneralPropertyMap<T> {} // .. and have our class
// inherit from it
//now our method becomes something like
private void TakeGeneralPropertyMap<T>(IList<IGeneralPropertyMap<T>> maps){}
// and you can do
var maps = new List<IGeneralPropertyMap<Object>> {
new GeneralPropertyMap<String>(),
new GeneralPropertyMap<Regex>()
};
//And finally pass the array in.
TakeGeneralPropertyMap<Object>(maps);
The caveat is that you can't use covariance with value types, so adding a new GeneralPropertyMap<int>() to our list fails at compile time.
cannot convert from 'GeneralPropertyMap<int>' to 'IGeneralPropertyMap<object>'
This approach may be more convenient than having a non-generic version of your classes/interfaces in case you want to constrain the types that GeneralPropertyMap can contain. In that case:
public interface IMyType {}
public class A : IMyType {}
public class B : IMyType {}
public class C : IMyType {}
public interface IGeneralPropertyMap<out T> where T : IMyType {}
allows you to have:
var maps = new List<IGeneralPropertyMap<IMyType>> {
new GeneralPropertyMap<A>(),
new GeneralPropertyMap<B>() ,
new GeneralPropertyMap<C>()
};
TakeGeneralPropertyMap(maps);

There is no direct equivalent to this in C#.
In C#, this would often be done by having your generic class implement a non-generic interface or base class:
interface IPropertyMap
{
// Shared properties
}
public class GeneralPropertyMap<T> : IPropertyMap
{
}
You could then pass an array of these:
IPropertyMap[] maps = new IPropertyMap[3];
// ...
TakePropertyMap(maps);

Make an interface from the members of GeneralPropertyMap (IGeneralPropertyMap), and then take an IGeneralPropertyMap[] as an argument.

Actually, you can get pretty close to a wildcard by using dynamic. This also works nicely if you have a non-generic superclass.
For example:
public class A
{
// ...
}
public class B<T> : A
{
// ...
}
public class Program
{
public static A MakeA() { return new A(); }
public static A MakeB() { return new B<string>(); }
public static void Visit<T>(B<T> b)
{
Console.WriteLine("This is B with type "+typeof(T).FullName);
}
public static void Visit(A a)
{
Console.WriteLine("This is A");
}
public static void Main()
{
A instA = MakeA();
A instB = MakeB();
// This calls the appropriate methods.
Visit((dynamic)instA);
Visit((dynamic)instB);
// This calls Visit(A a) twice.
Visit(instA);
Visit(instB);
}
}
How this works is explained in the C# documentation here.

Related

C#, How to pass a List of a Derived class to a method that receives a List of the Base class?

This is a simplified version of my code:
using System.Collections.Generic;
public abstract class FruitBox<T>
{
public T item;
public static T ChooseFirst(List<FruitBox<T>> fruitBoxes)
{
return fruitBoxes[0].item;
}
}
public class Apple
{
}
public class AppleBox : FruitBox<Apple>
{
}
public class FruitShop
{
List<AppleBox> appleBoxes = new List<AppleBox>();
public void Main()
{
AppleBox appleBox = new AppleBox();
appleBoxes.Add(appleBox);
AppleBox.ChooseFirst(appleBoxes); // => Error here
}
}
I have an error in the line:
AppleBox.ChooseFirst(appleBoxes);
cannot convert from System.Collections.Generic.List<AppleBox> to System.Collections.Generic.List<FruitBox<Apple>>
I tried:
AppleBox.ChooseFirst((List<FruitBox<Apple>>)appleBoxes);
But same error.
How do I have to proceed?
The reason for such behaviour is explained here. In short - classes do not support variance in C# and List<AppleBox> is not List<FruitBox<Apple>>.
What you can do:
"convert" collection (actually create a new one):
with OfType<>().ToList()
AppleBox.ChooseFirst(appleBoxes.OfType<FruitBox<Apple>>().ToList())
or just ToList
AppleBox.ChooseFirst(appleBoxes.ToList<FruitBox<Apple>>())
change ChooseFirst signature to work with covariant IEnumerable<out T> interface:
public abstract class FruitBox<T>
{
public T item;
public static T ChooseFirst(IEnumerable<FruitBox<T>> fruitBoxes)
{
return fruitBoxes.First().item;
}
}
You will have to hold the reference of the derived class into the base class variable
List<FruitBox<Apple>> appleBoxes = new List<AppleBox>();
FruitBox<Apple> appleBox = new AppleBox();
appleBoxes.Add(appleBox);
appleBox.ChooseFirst(appleBoxes);

Function specialization in generic class c#

I have a class called PointValue, PointValue and his inheritors can be created only by parametrized constructor that receives one float parameter.
I have a generic class that represents a list of points, template type must inherit from PointValue.
I need that one of the functions would have the ability to add points to the list, because I can't enforce using templates a parametrized constructor. my function gets a pointValueCreator to create the new point.
public class PointList<PointValueT> where PointValueT : PointValue
{
public void addPointToList(float f, Func<float,PointValueT> pointValueCreator)
{
// do something to f and then add a new point:
mylist.Add(pointValueCreator(f));
}
}
So now if I have something like this:
PointList<PointValue> bla = new PointList<PointValue>();
I can call my function like this:
bla.addPointToList(f, (myfloat) => new PointValue(myfloat));
My question is how can I create specialization for addPointToList for my PointValue inheritors, to avoid passing creators.
something like:
public void addPointToList(float f)
{
this.addPointToList(f, (myfloat) => new PointValue(myfloat));
}
I've tried to do it, but the compiler says:
Cannot implicitly convert type 'PointValue' to 'PointValueT'. An explicit conversion exists (are you missing a cast?)
I understand that c# doesn't have specialization, if that is the case, maybe some "design" trick can help me ?
Let's say I have PointValueA and PointValueB inherting, how can i avoid passing creators for each one of them manually ?
I would have thought that the most basic way to handle this is by passing the factory through the constructor, rather than for each call to addPointToList.
public class PointList<PointValueT> where PointValueT : PointValue
{
public PointList(Func<float, PointValueT> pointValueCreator)
{
this.pointValueCreator = pointValueCreator;
}
Func<float, PointValueT> pointValueCreator;
private List<PointValueT> mylist = new List<PointValueT>();
public void addPointToList(float f)
{
mylist.Add(pointValueCreator(f));
}
}
This would then be called like this:
PointList<PointValue> bla = new PointList<PointValue>((myfloat) => new PointValue(myfloat));
bla.addPointToList(f);
You cannot specialise generic in C# like you can with templates in C++.
It would be nice to be able to specify constructor arguments in constraints (i.e. where PointValueT : PointValue, new(float) ), but the language doesn't allow that.
There are a couple of solutions to achieve what you want:
1: use a creator pattern like you're already doing
2: instead of setting the float in the constructor, set it as a property.
public class PointValue
{
public float Value { get; set; }
}
public class PointList<PointValueT>
where PointValueT : PointValue, new()
{
public void addPointToList(float f)
{
// do something to f and then add a new point:
mylist.Add(new PointValueT { Value = f });
}
}
This does mean you can't make your PointValue immutable though.
You can sort of specialize using inheritance
public class PointValueList : PointList<PointValue>
{
public void addPointToList(float f)
{
addPointToList(f, (myfloat) => new PointValue(myfloat));
}
}
and then on that new inherited or specialized class you can just call
bla.addPointToList(f);
Also depending on your needs you can make the base class abstract and declare
public abstract void addPointToList(float f);
in the base class and then override in derived specialization classes
But yes, as Enigmativity suggested, passing factory through the constructor makes more sense at least with this simple example.

C# Access to a generic class member whose type is a generic argument type, only via an interface

I have a generic class who holds a member whose type is an argument type.
I want to be able to access this member only by one of the interface it implements.
The reason I want to access the member only via this interface, instead of enumerating all the concrete types it could be, is because there are a great number of those types.
So concretely I want to find an equivalent of line 61 in that code (it is a compilation error):
using System;
using System.Linq;
/* Interfaces */
public interface IArgumentClass
{
void IArgumentClassMethod();
}
public interface ISpecialArgumentClass
{
void ISpecialArgumentClassMethod();
}
public interface IContainerClass
{
void IContainerClassClassMethod();
}
/* Argument types */
public class ArgumentClass0 : IArgumentClass
{
public void IArgumentClassMethod(){}
}
public class SpecialArgumentClass0 : IArgumentClass, ISpecialArgumentClass
{
public void IArgumentClassMethod(){}
public void ISpecialArgumentClassMethod(){}
}
public class SpecialArgumentClass1 : IArgumentClass, ISpecialArgumentClass
{
public void IArgumentClassMethod() { }
public void ISpecialArgumentClassMethod() { }
}
/* Container types */
public class GenericContainer<T> : IContainerClass
where T : IArgumentClass, new()
{
public T t = new T();
public void IContainerClassClassMethod() { }
}
public class NonGenericContainer : IContainerClass
{
public void IContainerClassClassMethod(){}
}
/* main program */
public class Test
{
public static void Main()
{
// Instantiate
IContainerClass[] containers =
{
new GenericContainer<ArgumentClass0>(),
new GenericContainer<SpecialArgumentClass0>(),
new GenericContainer<SpecialArgumentClass1>(),
new NonGenericContainer()
};
// We want to call IContainerClassClassMethod methods on all instances:
foreach (IContainerClass container in containers)
container.IContainerClassClassMethod();
// We want to call ISpecialArgumentClassMethod on instances where it's possible:
foreach (IContainerClass container in containers)
{
if (container.GetType().IsGenericType && container.GetType().GetGenericTypeDefinition() == typeof(GenericContainer<>))
{
foreach (Type typeArgument in container.GetType().GetGenericArguments())
{
if (typeArgument.GetInterfaces().Contains(typeof(ISpecialArgumentClass)))
{
// Next line is a compilation error. How can I get a similar result?
GenericContainer<ISpecialArgumentClass> mySpecializedClassWithSpecialArgument = container as GenericContainer<ISpecialArgumentClass>;
mySpecializedClassWithSpecialArgument.t.ISpecialArgumentClassMethod();
}
}
}
}
}
}
Note: You can fork and edit the code here.
You get the compilation error because ISpecialArgumentClass is not of type IArgumentClass, but your GenericClass requires exactly this.
To solve this, you could introduce an empty interface which serves as base for both argument classes:
First, modify your interface declaration like this:
public interface IArgumentClassBase
{
}
public interface IArgumentClass : IArgumentClassBase
{
String GetNormalString();
}
public interface ISpecialArgumentClass : IArgumentClassBase
{
String GetSpecialString();
}
... then modify your generic class declaration like so:
public class GenericClass<T> : IContainerClass
where T : IArgumentClassBase, new()
Then the rest of your code should work...
A really simple solution is to just cast it to dynamic - you know it has a t field, so this should be safe to do.
if (typeArgument.GetInterfaces().Contains(typeof(ISpecialArgumentClass)))
{
dynamic mySpecializedClassWithSpecialArgument =
mySpecializedClass as dynamic;
ISpecialArgumentClass specialArgumentClass = mySpecializedClassWithSpecialArgument.t;
Console.WriteLine(specialArgumentClass.GetSpecialString());
}
Note
I tried to edit it in ideone, but it would not compile. I suspect it's targeting an older version of .NET - dynamic was introduced in .NET 4 (VS 2010). However, I've tested the code in 2013 and it works.

Defining interface dependency that implements generics

This will be generics 101 for many but below is sample code so I can understand better.
public interface IRecordedItemsProcessor<T>
{
ObservableCollection<RecordedItem> Load(string name);
void Save();
RecordedItem Parse(T itemToParse);
}
public class FileLoadingProcessor : IRecordedItemsProcessor<string>
{
public ObservableCollection<RecordedItem> Load(string name)
{
}
public void Save()
{
}
public RecordedItem Parse(string itemToParse)
{
}
}
public class MyClass
{
public MyClass(IRecordedItemsProcessor<T> processor)
{
}
}
The issue is that MyClass needs a dependency on IRecordedItemsProcessor<T> but will not compile as it does not know what T is. How can this be resolved? Making MyClass implement a seems odd as all it needs to do is call Load/Save
Thanks
First solution is the most simple one: lift generic declaration to class level, like
public class MyClass<T>
{
public MyClass(IRecordedItemsProcessor<T> processor)
{
}
}
Then you could instantiate MyClass as following:
var myClass = new MyClass<string>(new FileLoadingProcessor());
Console.WriteLine (myClass);
Second solution is a removing generic input from constructor and inferring types. Then you don't need to specify generic exactly from call. Class declaration will look like:
public class MyClass
{
public void Process<T>(IRecordedItemsProcessor<T> processor)
{
}
}
And then you can call simply
var my = new MyClass();
my.Process(new FileLoadingProcessor());
The Idea is that you always need to specify class-level generics explicitly, but method level generics can be inferred by the compiler.
Third solutions is to encapsulate creation mechanisms inside MyClassFactory. This is quite flexible, but it might seem a little bit complicated, because descendants of IRecordedItemsProcessor<T> don't define generic at class level, so we should go to implemented interfaces and grab there generic types. And only then we can construct Generic MyClass. Listing is given below:
public class MyClassFactory
{
public MyClass<T> MakeMyClassFor<T>(IRecordedItemsProcessor<T> processor)
{
var processorGenericType = processor.GetType()
.GetInterfaces()
.Single(intr=>intr.Name == "IRecordedItemsProcessor`1")
.GetGenericArguments()[0];
var myClassType = typeof(MyClass<>).MakeGenericType(processorGenericType);
return Activator.CreateInstance(myClassType, processor) as MyClass<T>;
}
}
Now you can create MyClass very simply
var myClassFactory = new MyClassFactory();
var res = myClassFactory.MakeMyClassFor(new FileLoadingProcessor());
Console.WriteLine (res);
All of these three approaches have their pros and cons. Consider taking into account the context, in which you are going to use them.
You could do the following:
Create a new interface IRecordedItemsProcessor (non-generic)
Move Load and Save to this IRecordedItemsProcessor
Make IRecordedItemsProcessor<T> inherit from this IRecordedItemsProcessor
Make MyClass expect IRecordedItemsProcessor in its constructor
This makes it clear that MyClass doesn't care what type the processor might be able to parse, or even that it can parse things at all - it only knows that it can save and load.
You could inherit from a non-generic marker interface, this removes the need to know about T in your class:
public interface IRecordedItemsProcessor
{
}
public interface IRecordedItemsProcessor<T> : IRecordedItemsProcessor
{
ObservableCollection<RecordedItem> Load(string name);
void Save();
RecordedItem Parse(T itemToParse);
}
And then you can use any IRecordedItemsProcessor like:
public class MyClass
{
public MyClass(IRecordedItemsProcessor processor)
{
}
}
The generic type, as written, is being declared on the MyClass constructor which means the generic type must be defined at the MyClass level:
public class MyClass<T>
{
public MyClass(IRecordedItemsProcessor<T> processor)
{
}
}
However, if the generic type was declared at a method level, it would only have to be defined at the method level:
public class MyClass
{
public void MyMethod<T>( IRecordedItemsProcessor<T> processor )
{
}
}
EDIT
Based on your comment:
I want a class that can call the Load/Save methods but not be worried
that T is.
Then you'll need 2 interfaces: 1 for the load/save and then one with the parsing. In this case, you could use inheritance:
public interface IRecordedItems
{
ObservableCollection<RecordedItem> Load( string name );
void Save();
}
public interface IRecordedItemsProcessor<T> : IRecordedItems
{
RecordedItem Parse( T itemToParse );
}
public class MyClass : IRecordedItems
{
#region Implementation of IRecordedItems
public ObservableCollection<RecordedItem> Load( string name )
{
throw new NotImplementedException();
}
public void Save()
{
throw new NotImplementedException();
}
#endregion
}
EDIT 2
Based on your gist example, the type dependency could be moved off of the interface and directly into the interface method:
public class RecordedItem {}
public interface IRecordedItemsProcessor
{
ObservableCollection<RecordedItem> Load( string name );
void Save();
RecordedItem Parse<T>( T itemToParse );
}
public class MyClass
{
private readonly IRecordedItemsProcessor _processor;
public MyClass( IRecordedItemsProcessor processor )
{
_processor = processor;
processor.Parse<string>( "foo" );
processor.Parse<int>( 10 );
processor.Parse<RecordedItem>( new RecordedItem() );
}
}

Using c# generics in a nested class

Consider the following class structure:
public class Foo<T>
{
public virtual void DoSomething()
{
}
public class Bar<U> where U : Foo<T>, new()
{
public void Test()
{
var blah = new U();
blah.DoSomething();
}
}
}
public class Baz
{
}
public class FooBaz : Foo<Baz>
{
public override void DoSomething()
{
}
}
When I go to use the nested class, I have something like the following:
var x = new FooBaz.Bar<FooBaz>();
It seems redundant to have to specify it twice. How would I create my class structure such that I can do this instead:
var x = new FooBaz.Bar();
Shouldn't there be some way on the where clause of the nested class to say that U is always the parent? How?
Update: Added methods for DoSomething() above to address some of the comments. It's important that when I call DoSomething, it addresses the overridden version. If I just use Foo instead of U, then the base implementation is called instead.
If class Bar does not need to be generic, why do you make it one?
This would work:
public class Foo<T, U> where U : Foo<T, U>
{
public class Bar
{
private T t;
private U u;
}
}
public class Baz
{
}
public class FooBaz : Foo<Baz, FooBaz>
{
}
And then
var bar = new FooBaz.Bar();
Of course all of this is totally abstract, so it might or might not apply to a practical example. What exactly are you trying to achieve here?
No, you can't merge that.
Inside Foo you have T and U, 2 different types and the compiler cannot make up a type for U, only constrain it.
Why do you introduce U at all? Can you not replace its use everywhere within the definition of Bar with Foo<T>?

Categories