I am trying to serialize custom EntityData class into Eyeshot proprietary file format. There is a great article about this (https://devdept.zendesk.com/hc/en-us/articles/360003318873-Eyeshot-Proprietary-File-Format),
it works fine if I serialize base class, however I can't serialize a class that is derived from my base class. Here is a sample, I tried to keep it as small as possible(please read comments along the way):
public class BaseClass
{
public int Id { get; set; }
public virtual BaseClassSurrogate ConvertToSurrogate() { return new BaseClassSurrogate(this); }
}
public class BaseClassSurrogate : Surrogate<BaseClass>
{
public BaseClassSurrogate(BaseClass myBaseClass) : base(myBaseClass) { }
public int Id { get; set; }
protected override BaseClass ConvertToObject()
{
var baseClass = new BaseClass();
CopyDataToObject(baseClass);
return baseClass;
}
protected override void CopyDataFromObject(BaseClass obj) { Id = obj.Id; }
protected override void CopyDataToObject(BaseClass obj) { obj.Id = this.Id; }
public static implicit operator BaseClass(BaseClassSurrogate surrogate) { return surrogate?.ConvertToObject(); }
public static implicit operator BaseClassSurrogate(BaseClass source) { return source?.ConvertToSurrogate(); }
}
And my derived class with its surrogate implementation:
public class DerivedClass : BaseClass
{
public int Number { get; set; }
public override BaseClassSurrogate ConvertToSurrogate() { return new DerivedClassSurrogate(this); }
}
public class DerivedClassSurrogate : BaseClassSurrogate
{
public DerivedClassSurrogate(DerivedClass baseClass) : base(baseClass) { }
public int Number { get; set; }
protected override BaseClass ConvertToObject()
{
var derivedClass= new DerivedClass();
CopyDataToObject(derivedClass);
return derivedClass;
}
protected override void CopyDataFromObject(BaseClass obj)
{
if (obj is DerivedClass derivedClass)
Number = derivedClass.Number;
base.CopyDataFromObject(obj);
}
protected override void CopyDataToObject(BaseClass obj)
{
if (obj is DerivedClass derivedClass)
derivedClass.Number = Number;
base.CopyDataToObject(obj);
}
//I don't understand do I need to call these in derived class as well?
//public static implicit operator BaseClass(BaseClassSurrogate surrogate) { return surrogate?.ConvertToObject(); }
//public static implicit operator BaseClassSurrogate(BaseClass source) { return source?.ConvertToSurrogate(); }
}
And here is FillModel method from FileSerializer class:
protected override void FillModel()
{
base.FillModel();
Model.Add(typeof(BaseClass), false)
.SetSurrogate(typeof(BaseClassSurrogate));
MetaType mt1 = Model[typeof(BaseClassSurrogate)]
.Add(1, "Id");
mt1.SetCallbacks(null, null, "BeforeDeserialize", null);
mt1.UseConstructor = false;
Model.Add(typeof(DerivedClass), false)
.SetSurrogate(typeof(DerivedClassSurrogate));
MetaType mt2 = Model[typeof(DerivedClassSurrogate)]
.Add(1, "Number");
mt2.SetCallbacks(null, null, "BeforeDeserialize", null);
mt2.UseConstructor = false;
}
This code gives me error:"No suitable conversion operator found for surrogate DerivedClass/DerivedClassSurrogate". Any help would be highly appreciated.
In FillModel() method you forgot to specify the hierarchy for your custom classes, try in this way:
protected override void FillModel()
{
base.FillModel();
Model.Add(typeof(BaseClass), false)
.AddSubType(1001, typeof(DerivedClass))
.SetSurrogate(typeof(BaseClassSurrogate));
Model[typeof(BaseClassSurrogate)]
.AddSubType(1001, typeof(DerivedClassSurrogate))
.Add(1, "Id")
.SetCallbacks(null, null, "BeforeDeserialize", null)
.UseConstructor = false;
Model[typeof(DerivedClassSurrogate)]
.Add(1, "Number")
.UseConstructor = false;
}
Related
I have a ParentClass. Two classes are inherit from it, FirstChildClass and SecondChildClass. A class MultipleValueTypes contains a Dictionary and a method that adds values to it. My intention is to be able to pass values of different classes, which inherit from the same abstract class to the value parameter of the Dictionary. Therefore, I initialize the dictionary with the value List<ParentClass> so that I would be able to add objects made with the child classes to the Dictionary. I can do this, but I cannot access them, therefore in the abstract class I create a way to tell them apart, a virtual method that both the children classes override to return their own class type.
I test the values they return against the enum itself and based on whether the condition is fulfilled, the object would be casted as what it is instead of a List<ParentClass>. Is this the wrong approach? Is this impossible?
I think it should work, because in my thinking the FirstObject and SecondObject are still objects of their respective classes, so casting should work and I should be able to access the overridden method.
What doesn't work: I cannot access the method that returns what type of class it is, because it only gets methods from the List<ParentClass>.
What I've tried so far: searching for a way to access the method, but I did not find any.
What I still need help with: everything mentioned above.
public abstract class ParentClass
{
public string Name { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
}
public class FirstChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public FirstChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the FirstChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public SecondChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the SecondChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public Dictionary<string, List<ParentClass>> ADictionary = new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if (!ADictionary.ContainsKey(Name))
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
class Program
{
static void Main(string[] args)
{
FirstChildClass FirstObject = new FirstChildClass("FirstObject");
SecondChildClass SecondObject = new SecondChildClass("SecondObject");
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if(TestDictionary.ADictionary["FirstObject"].TypeOfClass() == ParentClass.ChildClasses.FirstChildClass) ///List<ParentClass>' does not contain a definition for 'TypeOfClass' and no accessible extension method 'TypeOfClass' accepting a first argument of type 'List<ParentClass>' could be found (are you missing a using directive or an assembly reference?)
{
TestDictionary.ADictionary["FirstObject"] = (FirstChildClass)TestDictionary.ADictionary["FirstObject"]; ///Cannot convert type 'System.Collections.Generic.List<Dictionary.ParentClass>' to 'Dictionary.FirstChildClass
}
}
}
You forgot to use indexer of the list value of the key of the dictionary here:
==> TestDictionary.ADictionary["FirstObject"][0]
Here is your code now refactored too:
class Program
{
static void Main(string[] args)
{
var FirstObject = new FirstChildClass("FirstObject");
var SecondObject = new SecondChildClass("SecondObject");
FirstObject.ReturnMessage();
SecondObject.ReturnMessage();
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if ( TestDictionary.ADictionary["FirstObject"][0].TypeOfClass()
== ParentClass.ChildClasses.FirstChildClass )
{
TestDictionary.ADictionary["FirstObject"][0]
= (FirstChildClass)TestDictionary.ADictionary["FirstObject"][0];
}
Console.ReadKey();
}
}
public abstract class ParentClass
{
public string Name { get; set; }
public string RandomValue { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public virtual void ReturnMessage()
{
Console.WriteLine($"This is the {this.GetType().Name} instance");
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
}
public class FirstChildClass : ParentClass
{
public FirstChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
public SecondChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public readonly Dictionary<string, List<ParentClass>> ADictionary
= new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if ( !ADictionary.ContainsKey(Name) )
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
If the intention is to cast the whole list from List<ParentClass> to List<FirstChildClass> and List<SecondChildClass>, then Linq is your friend, just use the Cast function:
List<FirstChildClass> firstChildClasses = TestDictionary.ADictionary["FirstObject"]
.Cast<FirstChildClass>().ToList();
List<SecondChildClass> secondChildClasses = TestDictionary.ADictionary["SecondObject"]
.Cast<SecondChildClass>().ToList();
I need to be able to access a protected property/method on an object with the common base class to the calling scope. The compiler doesn't seem to like this at all.
class Base
{
protected int Data { get; set; }
}
class SubClasss1 : Base
{
}
class SubClasss2 :Base
{
public SubClasss1 MyFunction() {
SubClasss1 x = new SubClasss1();
x.Data = this.Data; // NOT HAPPY
return x;
}
}
I've figured this may work, but it doesn't
((Base)copy).Data = ...
This does work but is a bit ugly
class Base
{
protected int Data { get; set; }
protected int GetData(Base obj) { return obj.Data; }
protected void SetData(Base obj, int value) { obj.Data = value; }
}
class SubClasss1 : Base
{
}
class SubClasss2 : Base
{
public SubClasss1 MyFunction()
{
SubClasss1 x = new SubClasss1();
this.SetData(x, this.Data);
return x;
}
}
I was trying to avoid using protected internal as I don't want to clutter the public interface within the project.
This is because protected member can be accessed with in the derived class not outside of it. What you can do is add it to constructor like:
class SubClasss1 : Base
{
public SubClasss1(int data)
{
Data = data; // can be accessed within the class but not from outside
}
}
and then you would need to provide it:
class SubClasss2 : Base
{
public SubClasss1 MyFunction()
{
SubClasss1 copy = new SubClasss1(this.Data);
return copy;
}
}
One way can be create public set method in SubClasss2 and then you should be able to read the value of it and set it into SubClass1 in your Myfucntion.
class Base
{
protected int Data { get; set; }
protected int GetData(Base obj) { return obj.Data; }
protected void SetData(Base obj, int value) { obj.Data = value; }
}
class SubClasss1 : Base
{
public void SetData(Base obj, int value) { this.Data = value; }
}
class SubClasss2 : Base
{
public void SetData(Base obj, int value) { this.Data = value; }
public SubClasss1 MyFunction()
{
SubClasss1 x = new SubClasss1();
x.SetData(x, this.Data);
return x;
}
}
class Program
{
static void Main(string[] args)
{
SubClasss2 subClass2Obj= new SubClasss2();
subClass2Obj.SetData(subClass2Obj, 30);
var subClass1Obj = subClass2Obj.MyFunction();
}
}
Is it possible to have a method in a base class to modify a derived class' properties? I was thinking something like this:
public class baseclass
{
public void changeProperties(string propertyName, string newValue)
{
try
{
this.propertyName = newValue;
}
catch
{
throw new NullReferenceException("Property doesn't exist!");
}
}
}
You can solve your problem via reflection, because this reference's type will be equal actual type, i.e. type of derived class:
Solution:
public class baseclass
{
public void changeProperties(string propertyName, object newValue)
{
var prop = GetType().GetProperty(propertyName);
if (prop == null)
throw new NullReferenceException("Property doesn't exist!");
else
prop.SetValue(this, newValue);
}
}
Implementation:
public class Test : baseclass
{
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
var test = new Test();
test.changeProperties("Age", 2);
}
}
I'm working to DRY some code up and I'm running into the following situation. I've reworked the code to provide a better example of the scenario.
namespace SourceCode
{
public interface IFactory
{
public baseClass GenerateClass();
public bool IsUsable();
}
public abstract baseClass
{
...
}
public AClass:baseClass
{
...
}
public class FactoryA:IFactory
{
public baseClass GenerateClass()
{
return new AClass();
}
public bool IsUsable(){
{
return true if some condition;
}
}
public BClass:baseClass
{
...
}
public class FactoryB:IFactory
{
public baseClass GenerateClass()
{
return new BClass();
}
public bool IsUsable(){
{
return true if some condition;
}
}
public static class FactoryProvider
{
List<IFactory> factories
static FactoryProvider()
{
factories.Add(new FactoryA());
factories.Add(new FactoryB());
}
static List<baseClass> GetClasses()
{
return (from f in factories where f.IsUsable() select f).ToList();
}
}
}
namespace SourceCode.Tests
{
public class baseTests
{
public T GenericMethod<T>(){...}
}
public class ClassATests:baseTests
{
public void Test1()
{
... generic used in a method provided by the base class
}
}
public class ClassBTests:baseTests
{
public void Test1()
{
... generic used in a method provided by the base class
}
}
}
So the problem in my tests is that there are tests that will have to happen for every child class.
UPDATE=======================
I was able to solve my issue by doing the following.
namespace SourceCode.Tests
{
public class baseTests<I> where I: baseClass
{
public void Test1()
{
var result = GenericMethod<I>();
// The generic method will use ClassA for ClassATests
// and ClassB for ClassBTests
}
public T GenericMethod<T>(){...}
}
public class ClassATests:baseTests<ClassA>
{
}
public class ClassBTests:baseTests<ClassB>
{
}
}
Making your current A class generic could solve problems:
abstract class A
{
// protected members...
protected abstract A InternalGetData(List<A> src);
public void SharedMethodHappensAlways()
{
List<A> src = new List<A>();
var childResult = InternalGetData(src);
}
}
abstract class A<T> : A
where T: A
{
public T GetData(List<A> src)
{
return src.OfType<T>().FirstOrDefault();
}
protected override A InternalGetData(List<A> src)
{
return GetData(src);
}
}
class B : A<B>
{
}
class C : A<C>
{
}
Sample usage:
List<A> src = new List<A>() { new B(), new C() };
B b = new B();
b.SharedMethodHappensAlways();
B firstB = b.GetData(src); // returns first instance of B
C firstC = new C().GetData(src);
I have following code:
public abstract class Operand<T>
{
public T Value { get; protected set; }
public bool IsEmpty { get; protected set; }
public override string ToString()
{
return IsEmpty ? Value.ToString() : string.Empty;
}
}
public class DoubleOperand : Operand<Double> {}
public interface IOperandFactory<T>
{
Operand<T> CreateEmptyOperand();
Operand<T> CreateOperand(T value);
}
public class DoubleFactory: IOperandFactory<double>
{
public Operand<Double> CreateEmptyOperand()
{
//implementation
}
public Operand<Double> CreateOperand(double value)
{
//implementation
}
}
I simlified code to just show the structure.
Now I need associationDictionary that will return IOperandFactory for required Type:
Something like this:
var factoryDict =
new Dictionary<Type, IOperandFactory<>>() { { typeof(double), new DoubleFactory() } };
Could you help me to achieve it if it is possible?
To do that, you would need to have a non-generic interface (typically in addition to the generic interface), i.e. a non-generic Operand, with Operand<T> : Operand (could also be an interface), and a non-generic IOperandFactory with IOperandFactory<T> : IOperandFactory. The only other option is to store a Dictionary<Type, object>, and have the caller cast as necessary.
Here's the non-generic approach:
using System.Collections.Generic;
using System;
public interface IOperand
{
object Value { get; }
bool IsEmpty { get; }
}
public abstract class Operand<T> : IOperand
{
public T Value { get; protected set; }
object IOperand.Value { get { return Value; } }
public bool IsEmpty { get; protected set; }
public override string ToString()
{
return IsEmpty ? Value.ToString() : string.Empty;
}
}
public class DoubleOperand : Operand<double> { }
public interface IOperandFactory
{
IOperand CreateEmptyOperand();
IOperand CreateOperand(object value);
}
public interface IOperandFactory<T> : IOperandFactory
{
new Operand<T> CreateEmptyOperand();
Operand<T> CreateOperand(T value);
}
public class DoubleFactory : IOperandFactory<double>
{
public Operand<double> CreateEmptyOperand()
{
throw new NotImplementedException();
}
IOperand IOperandFactory.CreateEmptyOperand() {
return CreateEmptyOperand();
}
IOperand IOperandFactory.CreateOperand(object value) {
return CreateOperand((double)value);
}
public Operand<double> CreateOperand(double value)
{
throw new NotImplementedException();
}
}
static class Program
{
static void Main()
{
var factoryDict = new Dictionary<Type, IOperandFactory> {
{typeof (double), new DoubleFactory()}
};
}
}
If I understand correctly, you are trying to store a collection of generic types, where the generic type parameters may vary. If this is the case, it is not directly possible, as the following example illustrates:
// You have lists of different types:
List<double> doubleCollection = new List<double>();
List<string> stringCollection = new List<string>();
// Now to store generically:
var collection = new List<List< /* ... Which type parameter to use? ... */ >>();
What should be apparent here, is that it is not possible to deduce which type parameter to use. Instead (with regards to your example), you may want something like this instead:
public interface IOperand
{
}
public interface IOperand<T>
{
}
public interface IOperandFactory
{
IOperand CreateEmptyOperand();
IOperand CreateOperand(object value);
}
public interface IOperandFactory<T> : IOperandFactory
{
new IOperand<T> CreateEmptyOperand();
IOperand<T> CreateOperand(T value);
}
public class DoubleFactory : IOperandFactory<double>
{
public IOperand<double> CreateEmptyOperand()
{
throw new NotImplementedException();
}
public IOperand<double> CreateOperand(double value)
{
throw new NotImplementedException();
}
IOperand IOperandFactory.CreateEmptyOperand()
{
throw new NotImplementedException();
}
public IOperand CreateOperand(object value)
{
throw new NotImplementedException();
}
}
public class SomeContainer
{
public SomeContainer()
{
var factoryDict = new Dictionary<Type, IOperandFactory>()
{
{ typeof(double), (IOperandFactory)new DoubleFactory() }
};
}
}
This may not be the most elegant of solutions, but it would allow you to store different generic types in the same collection. An issue with this, however, is that the caller accessing such a collection would need to know what type to cast to. For example:
// ... Inside SomeContainer ...
public IOperandFactory<T> GetFactory<T>()
{
return (IOperandFactory<T>)factoryDict[typeof(T)];
}
So with this, you can get the DoubleFactory using:
IOperandFactory<double> doubleFactory = mSomeContainerInstance.GetFactory<double>();
IOperand<double> emptyOperand = doubleFactory.CreateEmptyOperand();
IOperand<double> filledOperand = doubleFactory.CreateOperand(1.0d);