I have extracted this from the real code and just implemented some things to give it context (I hope). I get the following error on the line with the recursive call to GetResourceVariable
CS1503: Argument 1: cannot convert from `CResourceGroup` to `TResource`
Argument type `CResourceGroup` is not assignable to parameter type `TResource`
What I am trying to do is call GetResourceVariable on an object of type TResource to get a certain variable value. These objects are part of a hierarchy so if the variable is not defined on the resource I want to traverse up the hierarchy and see whether a 'parent' has this variable defined and return that value.
This is where FromResource comes in. Now this FromResource should a group/folder type resource, but that has much of the properties of a resource, which you can see from the class inheritance hierarchy.
I don't get why I can't use a CResourceGroup (which is a CResDefs which is a CResource as the parameter to the generic function that has a where TResource : CResource I thought that the where constraint meant that only objects that are CResource (or inherited from CResource) could be the parameter? Somehow this last part seems not true!
I might be able to refactor the inheritance hierarchy but before trying that I would rather know why this is not possible as shown in C#?
using System;
using System.Collections.Generic;
public class Program
{
public class CResVariable
{
public string Value { get; set; }
}
public class CResVariableList : List<CResVariable>
{
public CResVariable GetByName(string name) { return null; }
}
public class CResource {
public CResVariableList ResVariables { get; set; }
public CResourceGroup FromResource
{
get
{
return this.GetFromResource(useChildrenList:true);
}
}
protected CResourceGroup GetFromResource(bool useChildrenList = false)
{
return null;
}
}
public class CResDefs : CResource {}
public class CResourceGroup : CResDefs {}
public class ResVariableSupport {
public string GetResourceVariable<TResource>(TResource resource, string variableName, bool recursive)
where TResource : CResource
{
CResVariable variable = resource?.ResVariables?.GetByName(variableName);
if (variable != null)
{
return variable.Value;
}
if (recursive)
{
return this.GetResourceVariable<TResource>(resource?.FromResource, variableName, true);
}
return "";
}
}
public static void Main() {
Console.WriteLine("Hello world!");
}
}
The only problem in your code is explicitly naming the generic parameter in the call to GetResourceVariable - you dont need to do that as it is implied from the call.
This works:
return this.GetResourceVariable(resource?.FromResource, variableName, true);
Code here: https://dotnetfiddle.net/LxUIxL
Related
So what I'm trying is to make a method that selects types that implement a generic class, with specific generic value that is only known at run-time.
I have tried something like this
public bool HasCommand(ITerminal owner)
{
var genericType = typeof(Command<>).MakeGenericType(owner.GetType());
var command = typeof(HelloCommand);
return command.GetInterfaces().Any(x => x.GetGenericTypeDefinition() == genericType
&& x.IsGeneric);
}
And hello command looks like this
public class HelloCommand : Command<HallTerminal>
But it always returns false.
Any solutions on what to change / do.
EDIT :
The command class looks like this
public class Command<T>
You can check whether the class is compatible with a given type using is operator:
public bool HasCommand(Terminal owner)
{
var gType = typeof(Command<>).MakeGenericType(owner.GetType());
var bType = typeof(HelloCommand);
if (owner is Command<HallTerminal>)
{
}
}
An example:
public class Person<T>
{
public int Id { get; set; }
}
public class Student : Person<Greeting>
{ }
public class StudentWarmGreeting : Person<WarmGreeting>
{ }
public class Greeting
{
public void SayHello()
{
Console.WriteLine("Hello, it is Greeting!:)");
}
}
public class WarmGreeting
{
public void SayHello()
{
Console.WriteLine("Hello, it is WarmGreeting!:)");
}
}
And you can check using is operator:
static void Main(string[] args)
{
if (studentGreeting is Person<Greeting>)
Console.WriteLine("person is Greeting");
if (studentWarmGreeting is Person<WarmGreeting>)
Console.WriteLine("person is WarmGreeting");
// Visual Studio is clever and it will say:
// "The given expression is never of the provided ('Program.Person') type"
if (studentWarmGreeting is Person<Greeting>)
Console.WriteLine("person is Greeting");
}
However, Visual Studio is clever and it will give a warning to us:
The given expression is never of the provided
('Program.Person') type
Solved the problem, but the issue of always getting false was that Command (which is implemented in HelloCommand) is not a interfence, hence always false.
To solve this issue you can do
command.BaseType.IsEquivalentTo(genericType)
to keep things simple I have two classes: ActionTaken and MovementTaken. MovementTaken is a derived class from ActionTaken. I have a Queue full of actions, and each action has a char that determines the type of action. (Every action has a correct type) I want to pass elements of the Queue to a function, that works specifically with a MovementTaken parameter, but since I'm using polymorphism the parameter is of type ActionTaken, but then I cannot use member variables from MovementTaken, but don't exist in ActionTaken. But if I set the function activateMovement's parameter to type MovementTaken, I believe there would be an error, saying you cannot convert a base type to a derived type. Here's the code:
public abstract class ActionTaken : MonoBehaviour
{
public char type;
public Transform minionTakingAction;
}
public class MovementTaken : ActionTaken
{
public int targetTileH;
public int targetTileV;
public MovementTaken(Transform _minionTakingAction, int _targetTileH, int _targetTileV)
{
type = 'M';
minionTakingAction = _minionTakingAction;
targetTileH = _targetTileH;
targetTileV = _targetTileV;
}
}
Queue<ActionTaken> actionTaken;
public void activateMovement(ActionTaken toActivate)
{//some code using toActivate's members targetTileH and targetTileV}
If you know the argument passed to the method is a MovementTaken instance, you can just downcast it:
public void activateMovement(ActionTaken toActivate)
{
MovementTaken casted = toActivate as MovementTaken;
// Do something with casted.targetTileH and/or caster.targetTileV
The advantage of Abstract classes is defining base implementation, or to force derived types into implementation details:
public abstract class ActionTaken : MonoBehaviour
{
public char Type { get; protected set; }
public Transform Target { get; }
// base ctor
protected ActionTaken(Transform target)
{
Type = '\0';
Target = target;
}
// Force implementation onto sub class
public abstract void Activate();
}
public class MovementTaken : ActionTaken
{
public int TileH { get; set; }
public int TileV { get; set; }
public MovementTaken(Transform target, int tileH, int tileV)
: base(target)
{
Type = 'M';
TileH = tileH;
TileV = tileV;
}
public override void Activate()
{
//some code using TileH and TileV
}
}
Therefore your calling code would be:
Queue<ActionTaken> actionTaken;
public void activateMovement(ActionTaken action)
{
action.Activate();
}
I'm also not sure what Type is being used for, but if you still need it, it might be better off as a constant defined in each class that derives from ActionTaken if you have more.
This can make sense if you end up filling your Queue<ActionTaken> with various derived movement types. Otherwise your ActivateMovement method could end up being a long switch statement.
An interface also might be advantageous here:
public interface IActionTaken
{
Transform Target { get; }
void Activate();
}
Which you would then replace your queue: Queue<IActionTaken> Actions
The code for invoking all of the actions in the queue could then be extremely straightforward:
while(Actions.Count > 0)
{
IActionTaken current = Actions.Dequeue();
current.Activate();
}
Before I begin, I want to state I realize this isn't the ideal way of doing this. However the calling class can't be changed according to the rules of the assignment. I have tried to understand and find a solution to this problem, but I have had no luck.
Below there is 1 superclass,TreeMangement (There can only be 1 superclass for these subclasses). There are 3 subclasses(apple, orange and banana). The "find" method must be in the TreeMangement superclass. I am not allowed to override the "find" method. With the current code, I will get a casting error in the calling class. It will state that a TreeMangement can't implicity be casted into a AppleTree,OrangeTree or BananaTree.
Now my question is, am I able to somehow pass the correct type back to the calling class no matter what type (Apple,Banana,Orange) is calling it, without casting in the calling class? If so, how? If not, references so I know there is absolutely no way of doing it.
public class TreeMangement
{
public string id {get; set;}
public TreeMangement()
{
id = this.GetType().Name+"|"+Guid.NewGuid();
}
public static TreeMangement Find(string idIn)
{
string type = idIn.Split('|')[0];
return Functions.GetObj(idIn, GetFilePath(type), type); //returns back the right type
}
}
public class AppleTree:TreeMangement
{
public string Name;
}
public class OrangeTree:TreeMangement
{
public string Name;
}
public class BananaTree:TreeMangement
{
public string Name;
}
///////Calling class////
AppleTree savedAppleTree = AppleTree.Find("SomeValidID");
OrangeTree savedOrangeTree = OrangeTree.Find("SomeValidID");
BananaTree savedBananaTree = BananaTree.Find("SomeValidID");
You can change the superclass to a generic superclass like this:
public class TreeMangement<T>
where T: class
{
...
public static T Find(string idIn)
{
return ... as T;
}
}
Now you are able to specifiy the return type in your subclasses like
public class AppleTree:TreeMangement<AppleTree>
{
public string Name;
}
public class OrangeTree:TreeMangement<OrangeTree>
{
public string Name;
}
public class BananaTree:TreeMangement<BananaTree>
{
public string Name;
}
This way your 3 find calls will compile just fine as the Find() call will return the correct type:
var savedAppleTree = AppleTree.Find("SomeValidID");
var savedOrangeTree = OrangeTree.Find("SomeValidID");
var savedBananaTree = BananaTree.Find("SomeValidID");
Bofore I would like to ask my question, please read the follwing classes:
public class JsonPackage<A> : USOPackage
{
public JsonPackage(PackageHeader header, object o) : base(header, StringCompressor.CompressString(JsonConvert.SerializeObject(o, Formatting.Indented))) { }
public new A Content
{
get
{
return JsonConvert.DeserializeObject<A>(this.getContentAsString());
}
}
new public string getContentAsString()
{
return StringCompressor.DecompressString(base.getContentAsString());
}
}
(this class includes USOPackage(!))
and a second class:
public class LoginResponsePackage : JsonPackage<LoginResponse>
{
public LoginResponsePackage(LoginResult result) : base(PackageHeader.USO_AUTH_LOGIN_RESPONSE, new LoginResponse(result)) { }
public class LoginResponse
{
public LoginResult Result;
public LoginResponse(LoginResult r)
{
this.Result = r;
}
}
public enum LoginResult
{
OK,
FailedPassword,
FailedUsername,
FailedProtocolVersion
}
}
Now I would like to convert a "USOPackage" to an "LoginResponsePackage" to get the "Content" of the package in the right type.
If i do it like that:
JsonPackage<LoginResponsePackage.LoginResponse> responsePackage = (JsonPackage<LoginResponsePackage.LoginResponse>)usopackage;
So if I try to get "Content" it works which means i get a LoginResponse by calling
responsePackage.Content
but when i convert the class like that
LoginResponsePackage responsePackage = (LoginResponsePackage)usopackage;
I am not able to access the LoginReponse. It just give me access to for instance: BeginInvoke(), Method, Target, Clone()
I don't know where this comes from..
So my question is what do i have to change in my code to be ablt to directly cast the package so i get a "LoginResponse" by accessing "LoginResponsePackage.Content"
The problem is in this line of code:
public class LoginResponsePackage : JsonPackage<LoginResponse>
The type LoginResponse in this context doesn't mean the nested class you've defined in LoginResponsePackage, it refers to some type outside the class, I guess a delegate from your description of the methods there. You are not inside the class scope yet, so you have to refer to the nested type via its name you would use outside the class: LoginResponsePackage.LoginResponse.
The fixed line:
public class LoginResponsePackage : JsonPackage<LoginResponsePackage.LoginResponse>
I have class which I want to export via MEF. In this example it's string type Displayer but in program will be many special type Displayers. I will do ImportMany<*IDisplayer> to get a list of available Displayers, and I will choose the Displayer from that list, for a given object to show.
My question how would be possible to make Display method type save? Or cast in it type safe? And still have Displayer usable via MEF.
P.S.
Using MEF I can't make interface like IDisplayer<*T>, because I will be not able to get a ImportMany<*IDisplayer<*T>> or something.
[DisplayableTypes(typeof(String))]
public class StringObjectDisplayer : IDisplayer
{
public void Display(object objectToDisplay)
{
var displayableObject = (string)objectToDisplay;
}
private Type GetAttributeParamenters()
{
return GetType().GetCustomAttributes(typeof(DisplayableTypesAttribute), true).OfType<DisplayableTypesAttribute>().First().SupportedType;
}
}
public class DisplayableTypesAttribute : ExportAttribute, IExportableElement
{
public DisplayableTypesAttribute(Type supportedType)
: base(typeof(IDisplayer))
{
SupportedType = supportedType;
}
public Type SupportedType { get; private set; }
}
public interface IDisplayer
{
void Display(object objectToDisplay);
}
public interface IExportableElement
{
Type SupportedType { get; }
}