i have a problem to create my code structure i don't now how to make it work
the problem in PlayListInfo<VerseTrack> ProgresList = new PlayListInfo<VerseTrack1>();
where it connot be converted
here is the code sample
public class PlayListInfo<_VerseTrack> : IPlayListInfo
where _VerseTrack : VerseTrack
{
public List<_VerseTrack> Tracks;
}
public class VerseTrack1: VerseTrack
{
}
public class VerseTrack2: VerseTrack
{
}
public class player
{
PlayListInfo<VerseTrack> ProgresList;
}
public class player1:player
{
PlayListInfo<VerseTrack> ProgresList = new PlayListInfo<VerseTrack1>();
}
public class player2:player
{
}
Generic types aren't inherited based on their type parameters. A PlayListInfo<QuranVerseTrack> is not a PlayListInfo<VerseTrack>
You could do:
PlayListInfo<VerseTrack1> ProgresList = new PlayListInfo<VerseTrack1>();
and then treat all of the items like a VerseTrack, but it's unclear if that's what you should do.
or you could do:
PlayListInfo<VerseTrack> ProgresList = new PlayListInfo<VerseTrack>();
and then add VerseTrack1 (or VerseTrack2) items to it (assuming it's a collection of some sort).
Side note: player1.ProgresList is hiding the base property, not overriding it.
If you are using .NET 4.0 or higher, here's another workaround. I introduce you covariance and contravariance
Assuming A is convertible(implicit reference conversion is available) to B,
X is covariant if X<A> is convertible to X<B>
Since covariance and contravariance only work with interface, you need to modify IPlayListInfo like this:
public interface IPlayListInfo<out _VerseTrack>
where _VerseTrack : VerseTrack
{
// blah blah ...
}
And this might work!
public class player1:player
{
// PlayListInfo<VerseTrack> ProgresList = new PlayListInfo<VerseTrack1>(); // old one
IPlayListInfo<VerseTrack> ProgressList = new PlayListInfo<VerseTrack1>() as IPlayListInfo<VerseTrack1>;
}
Related
I have created this simple generic interface:
public interface IInitializerSettings<in ViewerType> where ViewerType : Component
{
void Apply(ViewerType dataViewer);
}
And added an implementation for it:
public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
public void Apply(CustomGridLayout dataViewer)
{
Debug.Log("Applied");
}
}
public class CustomGridLayout : CustomLayout
{
// The implementation code
}
Now I try to use it like that:
public IInitializerSettings<CustomLayout> GetDefaultSettings()
{
return new MenuSettings();
}
But I get this error "Cannot convert type MenuSettings to return type IInitializerSettings"
I don't understand why it isn't allowed, CustomGridLayout inherits CustomLayout.
All I could find is this question, but this solution doesn't work for me (I can't use the out keyword).
The reason you cannot do this is because for a contravariant interface (specified by your use of in for the generic type parameter) you cannot implicitly convert it to an instance of a less derived type. I think the bullet points in the docs explains it fairly ok, if you think in terms of IEnumerable<T> (covariant) and Action<T> (contravariant).
As Selvin mentions in the comments the Apply method in MenuSettings expects an instance of CustomGridLayout, so trying to cast MenuSettings to IInitializerSettings<CustomLayout> is not possible because public void Apply(CustomGridLayout dataViewer) cannot handle a CustomLayout as input. Let me give an example:
public class CustomLayout
{
public void SetupCustomLayout() { ... }
}
public class CustomGridLayout : CustomLayout
{
public void SetupGrid() { ... }
}
public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
public void Apply(CustomGridLayout dataViewer)
{
dataViewer.SetupGrid();
}
}
// Later in the code...
var menuSettings = new MenuSettings();
// This cast is what GetDefaultSettings() is trying to do
var genericSettings = (IInitializerSettings<CustomLayout>)menuSettings;
var layout = new CustomLayout();
// Looking at the type of 'genericSettings' this following line should be possible
// but 'MenuSettings.Apply()' is calling 'dataViewer.SetupGrid()' which doesn't exist
// in 'layout', so 'layout' is not a valid input
genericSettings.Apply(layout);
So in relation to the docs you have defined IInitializerSettings<ViewerType> as a contravariant interface, but are trying to use it as a covariant interface - which is not possible.
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.
I have a custom class (let's call it MyClass) that looks like this:
public class MyClass
{
private List<MyClass> list;
private object data;
}
However, I want to get rid of the object property and instead use a generic class. So something like this:
public class MyClass<T>
{
private List<MyClass<T>> list;
private T data;
}
However, I am in need for this behavior:
MyClass<Foo> foo = new MyClass<Foo>;
foo.list = new List<MyClass<Bar>>;
So I need to be able to have different datatypes for the foo-instance and the list/data-property in foo. But the T's in the generic example will be the same and only allow this:
MyClass<Foo> foo = new MyClass<Foo>;
foo.list = new List<MyClass<Foo>>;
Each item in foo.list will again have a list that might be of a different type. By the time I compile MyClass I have no knowledge about what datatypes will be in the lists/data-property or how many levels there will be. How can I build this flexible structure?
Generics are designed to allow for the compiler to perform checks on type usage and they also provide some nifty additional benefits.
What you've described cannot be achieved with generics, if each time you're updating list with a list of a potentially different type then generics cannot help you.
However, if each of these types share a common base type or share a common interface then you could use that as your T for the list and that would allow you to use them.
If however each instance of MyClass allows only one type of List of MyClass<?> then you could revise MyClass as such:
public class MyClass<T, TList>
{
private List<MyClass<T, TList>> list;
private T data;
}
You can't achieve this goal with just one class. You will have to build one generic base class for each level with children, one base class for the lowest level without children and one derived class per hierarchy level.
The base classes would look like this:
public class MyClass<TData>
{
public TData Data { get; set; }
}
public class MyClass<TData, TDataChildren, TChildren> : MyClass<TData>
where TChildren : MyClass<TDataChildren>
{
public List<TChildren> List { get; set; }
}
The derived classes per Level would look like this:
public class Level0 : MyClass<Foo, Bar, Level1> { }
public class Level1 : MyClass<Bar, Fubar, Level2> { }
public class Level2 : MyClass<Fubar> { }
Usage:
var root = new Level0();
root.Data = new Foo();
root.List = new List<Level1>
{
new Level1()
{
Data = new Bar(),
List = new List<Level2>
{
new Level2()
{
Data = new Fubar()
}
}
}
};
Add a second type in MyClass.
public class MyClass<T, G>
{
private List<MyClass<G, T>> list;
private T data;
}
This is assuming that you don't care the type of the nested list inside your list.
But can you elaborate a bit more on the utility of your code because it is hard to tel just with abstract data.
I am trying to implement a very similar thing in C++ right now and am running into the same problem. The problem with templates is that they are strongly typed and MyClass<foo> is treated as a complete different and unrelated type as MyClass<bar>.
What I am playing with now is creating an abstract class that has pure virtual methods on it like GetInt, GetDouble, GetBool, GetString. I then want to have a templated Add that will instantiate the appropriate concrete class and add it to my vector. I'm not sure if it will work, but it's along these lines:
class Data
{
public:
template<typename T> Add(const std::string& key, const T& val)
{
Data* pData = NULL;
//test the type using std::numeric_limits to figure out which concrete
//type to use.
m_mapValues[key] = pData;
}
protected:
virtual int GetInt() const = 0;
virtual unsigned int GetUINT() const = 0;
virtual std::string GetString() const = 0;
//blah blah more types that you want to handle
private:
std::map<std::string,Data*> m_mapValues;
};
class UINTData : public Data
{
//implement pure virtual methods.
}
This is obviously incomplete, but I hope it gives you some ideas.
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.
I'm working with the .NET framework and I really want to be able to make a custom type of page that all of my website uses. The problem comes when I am trying to access the page from a control. I want to be able to return my specific type of page instead of the default page. Is there any way to do this?
public class MyPage : Page
{
// My own logic
}
public class MyControl : Control
{
public MyPage Page { get; set; }
}
UPDATE: This answer was written in 2011. After two decades of people proposing return type covariance for C# they have been implemented. See Covariant Returns in https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/.
It sounds like what you want is return type covariance. C# does not support return type covariance.
Return type covariance is where you override a base class method that returns a less-specific type with one that returns a more specific type:
abstract class Enclosure
{
public abstract Animal Contents();
}
class Aquarium : Enclosure
{
public override Fish Contents() { ... }
}
This is safe because consumers of Contents via Enclosure expect an Animal, and Aquarium promises to not only fulfill that requirement, but moreover, to make a more strict promise: that the animal is always a fish.
This kind of covariance is not supported in C#, and is unlikely to ever be supported. It is not supported by the CLR. (It is supported by C++, and by the C++/CLI implementation on the CLR; it does so by generating magical helper methods of the sort I suggest below.)
(Some languages support formal parameter type contravariance as well -- that you can override a method that takes a Fish with a method that takes an Animal. Again, the contract is fulfilled; the base class requires that any Fish be handled, and the derived class promises to not only handle fish, but any animal. Similarly, C# and the CLR do not support formal parameter type contravariance.)
The way you can work around this limitation is to do something like:
abstract class Enclosure
{
protected abstract Animal GetContents();
public Animal Contents() { return this.GetContents(); }
}
class Aquarium : Enclosure
{
protected override Animal GetContents() { return this.Contents(); }
public new Fish Contents() { ... }
}
Now you get both the benefits of overriding a virtual method, and getting stronger typing when using something of compile-time type Aquarium.
With interfaces I got around it by explicitly implementing the interface:
public interface IFoo {
IBar Bar { get; }
}
public class Foo : IFoo {
Bar Bar { get; set; }
IBar IFoo.Bar => Bar;
}
This is a feature for the upcoming C# 9.0 (.Net 5) of which you can download a preview version now.
The following code now builds successfully (without giving: error CS0508: 'Tiger.GetFood()': return type must be 'Food' to match overridden member 'Animal.GetFood()')
class Food { }
class Meat : Food { }
abstract class Animal {
public abstract Food GetFood();
}
class Tiger : Animal {
public override Meat GetFood() => default;
}
class Program {
static void Main() => new Tiger();
}
Placing this in the MyControl object would work:
public new MyPage Page {get return (MyPage)Page; set;}'
You can't override the property because it returns a different type... but you can redefine it.
You don't need covariance in this example, since it is relatively simple. All you're doing is inheriting the base object Page from MyPage. Any Control that you want to return MyPage instead of Page needs to redefine the Page property of the Control
Yes, it supports covariance, but it depends upon the exact thing you are trying to achieve.
I also tend to use generics a lot for things, which means that when you do something like:
class X<T> {
T doSomething() {
}
}
class Y : X<Y> {
Y doSomethingElse() {
}
}
var Y y = new Y();
y = y.doSomething().doSomethingElse();
And not "lose" your types.
I haven't tried it, but doesn't this work?
YourPageType myPage = (YourPageType)yourControl.Page;
Yes. There are multiple ways of doing this, and this is just one option:
You can make your page implement some custom interface that exposes a method called "GetContext" or something, and it returns your specific information. Then your control can simply request the page and cast:
var myContextPage = this.Page as IMyContextGetter;
if(myContextPage != null)
var myContext = myContextPage.GetContext();
Then you can use that context however you wish.
You can access your page from any control by walking up the parent tree. That is
myParent = this;
while(myParent.parent != null)
myParent = myParent.parent;
*Did not compile or test.
Or get the parent page in the current context (depends on your version).
Then what I like to do is this: I create an interface with the functions I want to use in the control (for example IHostingPage)
Then I cast the parent page 'IHostingPage host = (IHostingPage)Parent;' and I am all set to call the function on the page I need from my control.
I will do it in this way:
class R {
public int A { get; set; }
}
class R1: R {
public int B { get; set; }
}
class A
{
public R X { get; set; }
}
class B : A
{
private R1 _x;
public new R1 X { get => _x; set { ((A)this).X = value; _x = value; } }
}