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>
Related
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
I have a class Response with generic parameter:
public class Response<T> where T : class {
public bool Result;
public T Data;
}
Also, I have a class Instance with simple parameters
public sealed class Instance {
public long Rank { get; set; }
public int ID_Member { get; set; }
}
And then I have a class where I use last ones
public sealed class InstanceResponse : Response<IList<Instance>> { }
And I try to add a constructor to last class and don't understand how to do it
I've tried like there, but it's doesn't work, JsonString contains serialized class InstanceResponse
public sealed class InstanceResponse : Response<IList<Instance>> {
public InstanceResponse(string JsonString) {
this = JsonConvert.DeserializeObject<InstanceResponse>(JsonString);
}
}
I've got an error Cannot assign to 'this' because it is read-only
How it possible?
It's not possible to deserialize json to the object and assign it directly in ctor to the object itself using this keyword.
Provided that
Json contains serialized class InstanceResponse
You can do something like this:
public sealed class InstanceResponse : Response<IList<Instance>> {
public InstanceResponse(string JsonString) {
var response = JsonConvert.DeserializeObject<InstanceResponse>(JsonString);
this.Data = response.Data;
this.Result = response.Result;
}
}
Another possible solution is to deserialize json in a code that creates instance of InstanceResponse (call's ctor) somewhere.
Instead of:
var response = new InstanceResponse(json);
You could deserialize json right there:
var response = JsonConvert.DeserializeObject<InstanceResponse>(json);
P.S.
With that being said, an interesting point was raised by #Lasse Vågsæther Karlsen regarding the subject. It is actually possible to assign something to this however it is only working inside of a structs ctor and use cases for it are very limited...(thanks Lasse)
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");
I have a file that looks like the following:
public abstract class TestStep
{
public abstract bool DoWork();
public abstract List<TestStep> PrerequisiteSteps { get; set; }
public abstract string DisplayForm { get; }
}
class TestFunctions
{
public class A : TestStep
{
public override string DisplayForm { get { return "MainForm; } }
// remaining implementation goes here...
}
public class B : TestStep { // some implementation }
public class C : TestStep { // some implementation }
public static void NextStep() { }
}
I'd like to serialize the classes A, B, and C to an XML file. I can manually add instances of these classes to a List<TestStep> object and pass that to an XML serializer, but I'd like to programmatically accomplish this because I might add or remove classes in TestFunctions in the future. As a result, I've found that I can use reflection to get an array of the functions:
Type type = (typeof(TestEngineFunctions));
Type[] testEngineFunctions = type.GetNestedTypes(BindingFlags.Public);
However I'm not sure how to proceed from here. I have access to the name of the functions, I can get their properties as well, but ultimately I don't have an actual object to serialize.
Am I on the right track or is there another method better suited for this?
You can get a new instance of the objects like this:
ObjectType instance = (ObjectType)Activator.CreateInstance(objectType);
Since you may not know the ObjectType before run time you could use the dynamic type and don't cast:
dynamic instance = Activator.CreateInstance(objectType);
However, if you attempt to serialize right after you instantiate you'll just get the default values of the object in your XML.
[MAJOR EDITS, my first post was somewhat misleading. My appologies]
Given a class such as:
public class DatabaseResult{
public bool Successful;
public string ErrorMessage;
//Database operation failed
public static DatabaseResult Failed(string message) {
return new DatabaseResult{
Successful = true,
ErrorMessage = message
};
}
}
How can I implement subclasses such that I can add additional properties to represent data relevant to the particular operation (such as MatchedResult in the case of a SELECT type query) without the need to implement that static failure function? If I try to use plain inheritance, the return type will be of the parent class. Eg:
DoThingDatabaseResult : DatabaseResult {
public IEnumerable<object> SomeResultSet;
public static Successful(IEnumerable<object> theResults){
return new DoThingDatabaseResult {
Successful = true,
ErrorMessage = "",
SomeResultSet = theResults
};
}
//public static DatabaseResult Failed exists, but it's the parent type!
}
The goal is to avoid needing to copy the Failed static function for every subclass implementation.
Make it recursively generic:
public class BankAccount<T> where T : BankAccount<T>, new()
{
public T SomeFactoryMethod() { return new T(); }
}
public class SavingsAccount: BankAccount<SavingsAccount>{}
You'll note that I made the factory method non-static, because static methods aren't inherited.
You can't do this exactly as you have defined the question. The best way to tackle this is really to pull your factory out of the class completely:
public class BankAccount
{
}
public class SavingsAccount : BankAccount
{
}
public static class BankAccountFactory
{
public static T Create<T>() where T : BankAccount, new()
{
return new T();
}
}
Now the Factory has no dependency on the actual type. You can pass any derived class of BankAccount and get it back without doing any extra work or worrying about inheriting your factory method.
If I may, I'd like to expand upon StriplingWarrior. In fact, you can use static for the factory. This following code shows that a and c are the expected object types. The limit is you cannot use the factory on the base class itself.
private void Testit()
{
var a = SavingsAccount.Factory();
var c = CheckingAccount.Factory();
//var b = BankAccount.Factory(); //can't do this
}
public class BankAccount<T> where T : BankAccount<T>, new()
{
public static T Factory()
{
return new T();
}
}
public class SavingsAccount : BankAccount<SavingsAccount>
{
}
public class CheckingAccount : BankAccount<CheckingAccount>
{
}
In order to use inheritance, you need an instance of an object and a member of that object. In this case, for the object we can't use BankAccount/SavingsAccount because then we would already have what we're trying to get. This means we need an actual factory object, which is what most people are talking about when they talk about a factory. So if we pull that out into a Factory and use inheritance...
public class BankAccountFactory { public virtual GetAccount() { return new BankAccount(); } }
public class SavingsAccountFactory : BankAccountFactory { public override GetAccount() { return new SavingsAccount(); } }
But now how do we get an instance of the proper type? We've just pushed our problem one layer deeper.
Instead, what you probably want to do, is use some sort of configuration to determine the type, or pass the type you want into a method.
public BankAccount GetAccount(AccountType type) { /* */ }
or
public BankAccount GetAccount() { /* Access config */ }
For a simple answer to your question: You don't need to use generics or anything like that, you just need your method to not be static...