The code below gives compile time error:
Error 170 Cannot convert type 'Tests.ChangeListener' to 'Tests.BaseListener'
How do I get this to compile?
namespace Tests
{
[TestClass]
public class UnitTest1
{
[TestMethod]
public void ShouldCompile()
{
BaseListener<IChange> listener = (BaseListener<IChange>)new ChangeListener();
}
}
public interface IChange
{
}
public interface ISpecificChange : IChange
{
}
public abstract class BaseListener<T>
where T : IChange
{
}
public class ChangeListener : BaseListener<ISpecificChange>
{
}
}
Since you can't do contravariance or covaraiance (ie in and out) on an abstract class you'll probably want an interface for your listener. Modifying the above to look like this allows it to compile (note entities not mentioned remain the same as the original code - attributes stripped to save me needing to import references while testing):
public class UnitTest1
{
public void ShouldCompile()
{
IListener<IChange> listener = new ChangeListener();
}
}
public interface IListener<out T> {}
public abstract class BaseListener<T> : IListener<T>
where T : IChange
{
}
This is obviously adding in a step that you don't currently have and may not be able to use for whatever reasons but it is the simplest way to get the code compiling and I think do what you want.
Related
I have the following Classes:
public abstract class Gear<T> : ScriptableObject, IGear { ... }
public class Armor : Gear<ArmorStatsLevel> { ... }
public class Weapon : Gear<WeaponStatsLevel> { ... }
Now I had the following methods to list my instances:
public abstract class WidgetListArmor {
public void ActionSelected(Armor gear) {
if (...) GameSession.Equip(gear);
}
}
public abstract class WidgetListWeapon {
public void ActionSelected(Weapon gear) {
if (...) GameSession.Equip(gear);
}
}
Because this was kind of redundant, I thought of moving it all to a base clase:
public abstract class WidgetListGear<T> : MonoBehaviour {
public void ActionSelected(T gear) {
if (...) GameSession.Equip(gear);
}
}
public class WidgetListArmors : WidgetListGear<Armor> { ... }
public class WidgetListWeapons : WidgetListGear<Weapon> { ... }
And while this seems cleaner, I have a new problem now. Because T is a Generic, GameSession.Equip can't overload gear.
Did I chose a bad pattern to organize my code? Am I missing something from Generics that allows me to do this operation?
UPDATE
Here is the GameSession signatures:
public class GameSession {
public static bool Equip(Armor armor);
public static bool Equip(Weapon weapon);
}
Make Weapon and Armor implement an interface called IGear, for example:
public interface IGear
{ }
public class Weapon : IGear
{
//snip
}
public class Armor : IGear
{
//snip
}
Constrain the generic type to IGear:
public abstract class WidgetListGear<T> : MonoBehaviour
where T : IGear
{
public void ActionSelected(T gear) {
if (...) GameSession.Equip(gear);
}
}
And make GameSession.Equip take IGear as the parameter type.
What you're looking for is dynamic dispatch. I would suggest you try the following:
GameSession.Equip((dynamic)gear);
However, I don't think it's the best idea since you've tried to encode your Game rules in type system and right now you're starting a mini-compiler in runtime to perform a dispatch for you.
I'd like to point you to Eric Lippert's articles on that subject. Looks like you have similar issues with what he's described.
Part 4 describes the dynamic approach I've provided as well as its disadvantages. Part 5 provides a completely different approach. Overall, I highly recommend reading each part.
I was using generic types in C# and I am new to using generic types. So, right now I am stuck with a problem. I have some classes like these:
public class MyModel1
{
}
public class MyModel2
{
}
public class BaseClass<T>
{
}
public class ChildClass1 : BaseClass<MyModel1>
{
}
public class ChildClass2 : BaseClass<MyModel2>
{
}
public class AnotherClass
{
//What will be the syntax of declaring this method
//The syntax of the following method is wrong and incomplete.
//It's there just to give an idea about whai i want to do.
public void MyMethod<T>()
where T : BaseClass<..what to write..>
{
}
}
My question is what will be the correct syntax of declaring MyMethod if I want to call MyMethod like this:
MyMethod<ChildClass1>();
If I understood correctly, you try to filter "MyMethod" so that T is a class of type "ChildClass ...".
You can add a generic parameter to your function like this:
public void MyMethod<T, U>()
where T : BaseClass<U>
{
}
But then you have to call MyMethod in that way.
MyMethod<ChildClass1, MyModel1>();
So it's quite complicated to use.
Another solution is to create a new "blank" class :
public abstract class Base // mark it as abstract if you don't need to use it in your code
{
}
public class MyModel1
{
}
public class MyModel2
{
}
public class BaseClass<T> : Base //The class inherits the new class
{
}
public class ChildClass1 : BaseClass<MyModel1>
{
}
public class ChildClass2 : BaseClass<MyModel2>
{
}
public class AnotherClass
{
public void MyMethod<T>()
where T : Base
{
}
}
You've forgotten to mention the return type and adding <T> after the class name. For example, if the return type is void, you could declare the method as:
public void MyMethod<T>()
where T : BaseClass<T>
{
}
This will work (by which I mean it compiles)
public void MyMethod<T>()
where T : BaseClass<MyModel1>
{ }
so does this:
public void MyMethod<T>()
where T : ChildClass1
{ }
Further edit after reading your comment...
You can do this:
public class AnotherClass<TBaseClass, TModel> where TBaseClass : BaseClass<TModel>
{
public void MyMethod(TBaseClass input)
{ }
}
I have a term for this, hopefully non-offensive. I call it The Generic Rabbit Hole of Madness. It's what happens when we try to combine generics and inheritance so that one set of classes can accomplish a broad set of goals that become increasingly confusing, and we solve it by adding more generic parameters and more generic classes.
You reach the bottom of the hole if you
- use <dynamic>
- check to see what the actual type is using GetType(), typeof, or is
- get it to compile but can't remember what it's supposed to do
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.
I want two generic classes to be able to reference each other. I can't seem to get anything to compile. Tried this:
class Program
{
static void Main(string[] args)
{
}
public class ClassA<BT> where BT: ClassB<ClassA<BT>>
{
BT btvar;
}
public class ClassB<AT> where AT: ClassA<ClassB<AT>>
{
AT atvar;
}
}
This has a practical implementation, but I wanted to avoid a complicated explanation of my own code. I can create closed classes that obey the rule, I just can't seem to describe a generic class or interface for those closed instances.
As fas as I understand, this is impossible, and this is why:
You want A, with a template value of type B.
You want B, with a template value of type A.
If you create a new instance of A, the compiler has to check of T is of type B. To check if it's type B, it has to check if B is of type A, A of type B, etc etc.
You end up creating an endless loop.
The way I ended up doing it was by adding the class as one of its own type parameters. It's not too pretty, but it works.
public abstract class Saver<TSaver, TData>
where TSaver : Saver<TSaver, TData>
where TData : ISaveable<TData, TSaver>
{ ... }
public interface ISaveable<TData, TSaver>
where TData : ISaveable<TData, TSaver>
where TSaver : Saver<TSaver, TData>
{ ... }
public class WorkspaceWindow : ScalingWindow, ISaveable<WorkspaceWindow, WorkspaceWindowSaver>
{ ... }
public class WorkspaceWindowSaver : Saver<WorkspaceWindowSaver, WorkspaceWindow>
{ ... }
This is possible, the following is based on the answer to this question.
public class ClassA<BT, AT> :
where BT : ClassB<AT, BT>
where AT : ClassA<BT, AT>
{
BT btvar;
}
public class ClassB<AT, BT> :
where BT : ClassB<AT, BT>
where AT : ClassA<BT, AT>
{
AT atvar;
}
You won't be able to use the classes directly, you'll need to override them.
public ClassAImp : ClassA<ClassBImp, ClassAImp>
public ClassBImp : ClassB<ClassAImp, ClassBImp>
So you may as well make ClassA and ClassB abstract.
this will compile, but I would like to see you instantiate either ClassA or ClassB:
public class ClassA<TBt> where TBt : ClassB<TBt>
{
TBt _btvar;
}
public class ClassB<TAt> : ClassA<TAt> where TAt : ClassB<TAt>
{
TAt _atvar;
}
"Why would you want to?" sounds like a good question to me. The point of Generics it to allow you to abstract a class to allow it to use multiple types. If the constraint limits the type to a concrete type, you are only allowing the type and its subclasses. If you aren't doing this for subclasses, don't use generics. If you are, how about using an interface?
public interface IClassA<ITB> { }
public interface IClassB<ITA> { }
public class ClassA<AT,BT> : IClassA<BT> where BT : IClassB<AT>
{
BT btvar;
}
public class ClassB<BT,AT> : IClassB<AT> where AT : IClassA<BT>
{
AT atvar;
}
public class ClassADerivedClosed : ClassA<ClassADerivedClosed, ClassBDerivedClosed> { }
public class ClassBDerivedClosed : ClassB<ClassBDerivedClosed, ClassADerivedClosed> { }
At first, I have gone over similar questions already, but i still think my problem is something different.:)
I have an interface :
namespace TEDLibrary
{
public interface ILogWriter
{
void WriteLog(ILogRecord log);
}
}
and i have an implementation class :
namespace TEDLibrary
{
public class LogWriter : ILogWriter
{
public LogWriter()
{
}
public void WriteLog(ILogRecord log)
{
}
}
}
As you see classes and members are public already.
However i get
Inconsistent accessibility: parameter type 'TEDLibrary.ILogRecord' is
less accessible than method
'TEDLibrary.ILogWriter.WriteLog(TEDLibrary.ILogRecord)'
I tried to declare WriteLog method in interface as public but it is not allowed.
ILogRecord should be public too.