I'm creating a child object from a parent object. So the scenario is that I have an object and a child object which adds a distance property for scenarios where I want to search. I've chosen to use inheritance as my UI works equivalently with either a search object or a list of objects not the result of a location search. So in this case inheritance seems a sensible choice.
As present I need to generate a new object MyObjectSearch from an instance of MyObject. At present I'm doing this in the constructor manually by setting properties one by one. I could use reflection but this would be slow. Is there a better way of achieving this kind of object enhancement?
Hopefully my code below illustrates the scenario.
public class MyObject {
// Some properties and a location.
}
public class MyObjectSearch : MyObject {
public double Distance { get; set; }
public MyObjectSearch(MyObject obj) {
base.Prop1 = obj.Prop1;
base.Prop2 = obj.Prop2;
}
}
And my search function:
public List<MyObjectSearch> DoSearch(Location loc) {
var myObjectSearchList = new List<MyObjectSearch>();
foreach (var object in myObjectList) {
var distance = getDistance();
var myObjectSearch = new MyObjectSearch(object);
myObjectSearch.Distance = distance;
myObjectSearchList.add(myObjectSearch);
}
return myObjectSearchList;
}
The base class needs to define a copy constructor:
public class MyObject
{
protected MyObject(MyObject other)
{
this.Prop1=other.Prop1;
this.Prop2=other.Prop2;
}
public object Prop1 { get; set; }
public object Prop2 { get; set; }
}
public class MyObjectSearch : MyObject
{
public double Distance { get; set; }
public MyObjectSearch(MyObject obj)
: base(obj)
{
this.Distance=0;
}
public MyObjectSearch(MyObjectSearch other)
: base(other)
{
this.Distance=other.Distance;
}
}
This way the setting of properties is handled for all derived classes by the base class.
You can use reflection to copy properties.
public class ChildClass : ParentClass
{
public ChildClass(ParentClass ch)
{
foreach (var prop in ch.GetType().GetProperties())
{
this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(ch, null), null);
}
}
}
There is no easy way to do this, unfortunately. As you said, you would either have to use reflection, or create a "Clone" method that would generate a new child object using a parent object as input, like so:
public class MyObjectSearch : MyObject {
// Other code
public static MyObjectSearch CloneFromMyObject(MyObject obj)
{
var newObj = new MyObjectSearch();
// Copy properties here
obj.Prop1 = newObj.Prop1;
return newObj;
}
}
No matter what, you're either going to end up writing reflection code (which is slow), or writing each property out by hand. It all depends on whether or not you want maintainability (reflection) or speed (manual property copy).
A generic solution would be to serialize it to json and back. In the json-string is no information about the class name from which it was serialized.
Most people do this in javascript.
As you see it works well for pocco objects but i don't guarantee that it works in every complex case. But it does event for not-inherited classes when the properties are matched.
using Newtonsoft.Json;
namespace CastParentToChild
{
public class Program
{
public static void Main(string[] args)
{
var p = new parent();
p.a=111;
var s = JsonConvert.SerializeObject(p);
var c1 = JsonConvert.DeserializeObject<child1>(s);
var c2 = JsonConvert.DeserializeObject<child2>(s);
var foreigner = JsonConvert.DeserializeObject<NoFamily>(s);
bool allWorks = p.a == c1.a && p.a == c2.a && p.a == foreigner.a;
//Your code goes here
Console.WriteLine("Is convertable: "+allWorks + c2.b);
}
}
public class parent{
public int a;
}
public class child1 : parent{
public int b=12345;
}
public class child2 : child1{
}
public class NoFamily{
public int a;
public int b = 99999;
}
// Is not Deserializeable because
// Error 'NoFamily2' does not contain a definition for 'a' and no extension method 'a' accepting a first argument of type 'NoFamily2' could be found (are you missing a using directive or an assembly reference?)
public class NoFamily2{
public int b;
}
}
If a shallow copy is enough, you can use the MemberwiseClone method.
Example:
MyObject shallowClone = (MyObject)original.MemberwiseClone();
If you need a deep copy, you can serialize/deserialize like this: https://stackoverflow.com/a/78612/1105687
An example (assuming you write an extension method as suggested in that answer, and you call it DeepClone)
MyObject deepClone = original.DeepClone();
I first came accros this question when I was looking for doing this.
If you are able to work with C# 9 and record-classes. You only have to create a new constructor in the sub-class taking in a base class object and hand it over to the subclass:
public record MyObject {
...
}
public record MyObjectSearch :MyObject
{
public MyObjectSearch(MyObject parent) : base(parent) { }
...
}
Then you can create the child object like this:
MyObject parent = new();
MyObjectSearch m = new MyObjectSearch(parentObj) { Distance = 1.1};
Credits to https://stackoverflow.com/a/64573044/2582968
Seems natural for the base object to have constructor with parameters for its properties:
public class MyObject
{
public MyObject(prop1, prop2, ...)
{
this.Prop1 = prop1;
this.Prop2 = prop2;
}
}
So then, in your descendant object you can have:
public MyObjectSearch(MyObject obj)
:base(obj.Prop1, obj.Prop2)
This reduces duplication related to assignments. You could use reflection to automatically copy all properties, but this way seems more readable.
Note also, that if your classes have so much properties that you're thinking about automatizing of copying of the properties, then they are likely to violate the Single Responsibility Principle, and you should rather consider changing your design.
There are libraries to handle this; but if you just want a quick implementation in a few places, I would definitely go for a "copy constructor" as previously suggested.
One interesting point not mentioned is that if an object is a subclass, then it can access the child's private variables from the within the parent!
So, on the parent add a CloneIntoChild method. In my example:
Order is the parent class
OrderSnapshot is the child class
_bestPrice is a non-readonly private member on Order. But Order can set it for OrderSnapshot.
Example:
public OrderSnapshot CloneIntoChild()
{
OrderSnapshot sn = new OrderSnapshot()
{
_bestPrice = this._bestPrice,
_closed = this._closed,
_opened = this._opened,
_state = this._state
};
return sn;
}
NOTE: Readonly member variables MUST be set in the constructor, so you will have to use the child constructor to set these...
Although I don't like "up-sizing" generally, I use this approach a lot for analytic snapshots...
Related
What I am trying to do is find the most elegant way to create a "pointer-like" class for a specific object/class type that I have in a project.
What I mean is a little confusing without an example. Take this really simple class:
public class MyClass
{
private string _name;
public string GetName() { return _name; }
public void SetName(string name) { _name = name; }
}
I want to create a second class which is like a pointer to it like this:
public class MyClassPtr
{
private MyClass _obj;
public bool IsValid = false;
public MyClassPtr(MyClass obj) { _obj = obj; IsValid = true; }
public void InvalidatePtr()
{
IsValid = false;
obj = null;
}
// SOME MAGIC HERE?
}
The challenge: The key is that I want to elegantly have MyClassPtr provide an interface to all of the public methods/members in MyClass without writing wrappers and/or accessors around each method/member.
I know that I could do this:
public class MyClassPtr
{
public string GetName() { return _obj.GetName(); }
...
}
But that's what I want to avoid. Is there some fundamental abstraction that I don't know of that I can apply to MyClassPtr to allow it to easily re-expose the methods/members in MyClass directed through _obj? I do NOT want MyClassPtr to inherit MyClass. Should MyClassPtr be a type instead, and some trick with accessors to expose the methods/members of MyClass?
Edit: More context on why I am looking for such a design through an example. Here is the overall goal. Imagine a platform that parses through data about people and when it finds information about a person, it creates an instance of Person with that information. You could get a handle to that person like:
Person person1 = platform.GetPerson(based_on_data);
Now, imagine the platform had two instances of Person that it thought were different people, but all of a sudden information came in that strongly suggested those two instances actually refer to the same person. So, the platform wants to merge the instances together in to a new object, let's call it personX.
Now, floating around in the platform someone had a copy of one of those two instances that got merged, which was person1. What I want to do is on-the-fly replace person1 with personX. Literally, I want person1==personX to be true, NOT just that they are two different objects with the same data. This is important since the platform could make a change to personX and unless the two objects are literally equal, a change to personX would not be automatically reflected in person1.
Since I can't on-the-fly replace person1 with personX I had that idea that I wouldn't give direct access to Person, instead I would give access to PersonPtr which the platform (on-the-fly) can change what Person it is pointing to. This would insurance that once person1ptr gets updated to point to personX, if a change is made in personX it will be seen in person1ptr
You could of course use something like
public class MyClassWrapper
{
MyClass _obj;
public MyClassWrapper(MyClass obj)
{
_obj = obj;
}
public void Invoke(Action<MyClass> action)
{
action(_obj);
}
public U Invoke<U>(Func<MyClass, U> func)
{
return func(_obj);
}
public void ChangeTo(MyClass obj)
{
_obj = obj;
}
}
Given your class looks like
public class MyClass
{
public string Name { get; set; }
}
Example:
var person1 = new MyClass { Name = "Instance1" };
var person2 = new MyClass { Name = "Instance2" };
var wrapper = new MyClassWrapper(person1);
wrapper.Invoke(x => x.Name += "original");
var x = wrapper.Invoke(x => x.Name); // Instance1original
wrapper.ChangeTo(person2);
var y = wrapper.Invoke(x => x.Name); // Instance2
but it has a major drawback: you can't access members directly, so you can't bind the data (to a DataTable or a Control).
It would be better to implement all members of your class also in your wrapper class. If you're afraid changes in your class will be forgotten to be implemented in your wrapper, just use an interface:
public interface IMyClass
{
string Name { get; set; }
}
public class MyClass : IMyClass
{
public string Name { get; set; }
}
public class MyClassWrapper: IMyClass
{
MyClass _obj;
public MyClassWrapper(MyClass obj)
{
_obj = obj;
}
public string Name
{
get { return _obj.Name; }
set { _obj.Name = value; }
}
}
Note that regardless which approach you use, you'll have to always keep a reference to the wrapper instance to actually change the underlying instance (using something like static aside).
Also, changing the underlying instance of such a wrapper without telling the component using it that it changed don't seem to be a good idea. Maybe your system is simple enough to get away with a wrapper; that's something you have to decide for yourself.
Maybe your wrapper should simply have an Invalid flag (and/or use an event to signal a change of the underlying object.). Once the underlying object is merged, it is set to true and each member access should throw an exception. This would force the component using the wrapper to deliberately react to changes and to reload the data from your service.
All in all, I think using such a wrapper will just clutter up your code and be error prone (just imagine adding multithreading to the mix). Think twice if you really need this wrapper.
Why not just simply ask your service for a new instance of your class everytime you use it (the service can simply use a cache)? Sure, you can't prevent that someone somewhere keeps a reference; but at least you'll keep your sanity.
I need to determine which object my code is working with at a certain point and write out only the properties specific to that class. I cannot figure out how to do it. I was told I can do it, but I cannot figure it out. Can someone please show me how to determine which object I am working with and write the properties specific to that class only?
I've looked at other questions asked, but am not smart enough to make it fit my example.
Below, I've re-created an example of the code I am working with. I can see all the code, but I am allowed to only work in one method (for this example called "MethodIAmWorkingIn"). Only modifications I am allowed to make are in that method.
public class Program
{
static void Main(string[] args)
{
TestDetailsAndResultsContainer container = new TestDetailsAndResultsContainer();
DerivedClass1 derivedClass1 = new DerivedClass1();
derivedClass1.DerivedClass1Prop1 = "DerivedClass1Prop1";
derivedClass1.DerivedClass1Prop2 = "DerivedClass1Prop2";
DerivedClass2 derivedClass2 = new DerivedClass2();
derivedClass2.DerivedClass2Prop1 = "DerivedClass2Prop1";
derivedClass2.DerivedClass2Prop2 = "DerivedClass2Prop2";
container.TestDetails.Add(derivedClass1);
container.TestDetails.Add(derivedClass2);
TestResult testResult = new TestResult();
testResult.TestResultProp1 = "TestResultProp1";
testResult.TestResultProp2 = "TestResultProp2";
container.Data.Add(testResult);
Program p = new Program();
p.MethodIAmWorkingIn(container);
}
private void MethodIAmWorkingIn(TestDetailsAndResultsContainer container)
{
// I need to see if the container variable holds a DerivedClass1 or DerivedClass2 object.
foreach (var result in container.TestDetails)
{
var classINeedToDetermine = container.TestDetails.FirstOrDefault(m => m.TestDetailsProp1 == result.TestDetailsProp1);
if (classINeedToDetermine is DerivedClass1)
{
classINeedToDetermine = result as DerivedClass1;
}
else if (classINeedToDetermine is DerivedClass2)
{
classINeedToDetermine = result as DerivedClass2;
}
// Now I need to use the classINeedToDetermine object and write its specific properties.
// ???????????????????? I am stuck at this point ??????????????????
// I need to write one or the other below. Can this be done?
// If it is DerivedClass1, I need to write out those properties only.
Console.WriteLine(classINeedToDetermine.DerivedClass1Prop1);
Console.WriteLine(classINeedToDetermine.DerivedClass1Prop2);
// OR
// If it is DerivedClass2, I need to write out those properties only.
Console.WriteLine(classINeedToDetermine.DerivedClass2Prop1);
Console.WriteLine(classINeedToDetermine.DerivedClass2Prop2);
}
}
}
public class TestDetailsAndResultsContainer
{
public TestDetailsAndResultsContainer()
{
this.Data = new List<TestResult>();
this.TestDetails = new List<TestDetails>();
}
public List<TestDetails> TestDetails { get; set; }
public List<TestResult> Data { get; set; }
}
public abstract class TestDetails
{
public string TestDetailsProp1 { get; set; }
public string TestDetailsProp2 { get; set; }
}
public class TestResult
{
public string TestResultProp1 { get; set; }
public string TestResultProp2 { get; set; }
}
public class DerivedClass1 : TestDetails
{
public string DerivedClass1Prop1 { get; set; }
public string DerivedClass1Prop2 { get; set; }
}
public class DerivedClass2 : TestDetails
{
public string DerivedClass2Prop1 { get; set; }
public string DerivedClass2Prop2 { get; set; }
}
The as keyword does not do what you think it does.
Your classINeedToDetermine is a variable of type TestDetails. You can assign a subclass instance to it, but you still cannot access that subclasses specific properties via that variable.
You just need some scope:
if (classINeedToDetermine is DerivedClass1)
{
var derived1 = (DerivedClass1)result;
Console.WriteLine(derived1.DerivedClass1Prop1);
// etc
}
else if (classINeedToDetermine is DerivedClass2)
{
var derived2 = (DerivedClass2)result;
Console.WriteLine(derived2.DerivedClass2Prop1);
// etc
}
This kind of thing is not fun to maintain though.
Another way of doing it would be to use polymorphism: Your TestDetails class could define an abstract method called PrintProperties, and all your subclasses could implement it.
Then you just have to call PrintProperties on every object, without worrying about which subclass they are.
I'm not completely sure on what objects mean what here, but it should be something like this:
foreach(var v in result.GetType().GetProperties())
{
if(v.DeclaringType == result.GetType())
{
Console.WriteLine(v.GetValue(result));
}
}
Again, I wasn't totally clear on your usage of classINeedToDetermine versus result, but you can change those as you see so fit. I chose result as my example since classINeedToDetermine was null by that part of your code.
And by the way, this section of your code is redundant. It should be removed for clarity and efficiency.
if (classINeedToDetermine is DerivedClass1)
{
classINeedToDetermine = result as DerivedClass1;
}
else if (classINeedToDetermine is DerivedClass2)
{
classINeedToDetermine = result as DerivedClass2;
}
Edit:
On the other hand, if performance is more important to you than being scalable (read: if you know or have control over all the classes you'll be dealing with), you could use this is section to do something less, I hate to use this word for this, "generic."
if (classINeedToDetermine is DerivedClass1)
{
var typed = (DerivedClass1)result;
Console.WriteLine(typed.DerivedClass1Prop1);
Console.WriteLine(typed.DerivedClass1Prop2);
}
else if (classINeedToDetermine is DerivedClass2)
{
var typed = (DerivedClass2)result;
Console.WriteLine(typed.DerivedClass2Prop1);
Console.WriteLine(typed.DerivedClass2Prop2);
}
You can use Type.GetProperties to get all Properties for your class. Then you need to get the MethodInfo for the Get method via GetMethod.
Once you have the MethodInfo you can call Invoke, passing in your Derived Class. You can write then write the result to the Console.
This is how my class object looks like:
Class MyInfo :IDisposable
{
List<MYObject> list;
public long X { get; private set; }
public IList<RasterFieldInfo> FieldInfo
{
get
{
return _ fields.AsReadOnly();
}
}
}
I do have an object MyInfo which is read-only (no public setter), I am looking an efficient way to make it writeable.
I cannot make this object as writeable (i.e. I cannot make setters as public) because that will give an impression to user that he is making changes to original object (while that is not true) and due to other reasons. What I am looking for is:
Minimal code duplication, this class has lots of code inside it.
Ease of use for the person going to use this object.
Best possible design and implementation.
I cannot make any setters as public to make it writeable.
Editable object usage will be as follows:
MyInfo obj = ds.GetInfo();
MyInfo editableObj = Obj.CreateEditableObject();
….
//Modify members of editableObj
…
Ds.SetInfo(editableObj);
Issue is how to provide an editable object of the same type by calling CreateEditableObject method.
You can use this pattern (sadly I don't remember how its called)
class MyInfo
{
public int MyProperty{ get; private set; }
public MyInfo WithMyProperty(int value)
{
return new MyInfo(){ MyProperty = value };
}
}
MyInfo obj = ds.GetInfo();
MyInfo modified = obj.WithMyProperty(1234);
The original object is of course not modified.
Final solution:
public class CustomOptionMetadata : OptionMetadata
{
public CustomOptionMetadata(OptionMetadata optionMetadata) : base()
{
this.Description = optionMetadata.Description;
this.ExtensionData = optionMetadata.ExtensionData;
this.Managed = optionMetadata.IsManaged;
this.Label = optionMetadata.Label;
this.MetadataId = optionMetadata.MetadataId;
this.Value = optionMetadata.Value;
}
public string MappedName { get; set; }
public bool? Managed { get; set; }
}
.
foreach (MappingEntity meAtt in mappingEntityList.FindAll(me => me.ParentID == meEnt.ID))
{
CRMOrganizationEntityAttribute crmOrganizationEntityAttribute = new CRMOrganizationEntityAttribute(meAtt.ID, meAtt.Name, true);
if (meAtt.IsPicklist)
{
List<OptionMetadata> optionMetadataList = GetAttributePickList(meEnt.Name, meAtt.Name);
if (optionMetadataList.Count > 0)
{
crmOrganizationEntityAttribute.OptionMetadataColl = optionMetadataList.Select<OptionMetadata, CustomOptionMetadata>(metadata => new CustomOptionMetadata(metadata)).ToList();
}
else
{
}
}
CRMOrgEnt.CRMAttributeNameList.Add(crmOrganizationEntityAttribute);
}
============================================================================
I am currently working on a mapping application, which already has a lot of custom objects. In an attempt to limit the lookups and definition of the classes, I thought about extending the already existing classes which I need anyways.
The OptionMetaDataCollection is part of the Microsoft.Xrm.SDK.Metadata library and has the OptionMetaData object in its Ilist.
Now I would like to create something like this:
public partial class CustomOptionMetadataCollection : OptionMetadataCollection
{
public CustomOptionMetadataCollection() : base() { }
}
public partial class CustomOptionMetadata : OptionMetadata
{
public CustomOptionMetadata() : base() { }
public string MappedName { get; set; }
}
But how would I change the Ilist<OptionMetaData> which is currently in the OptionMetadatacollection to my IList<CustomOptionMetaData>. I am aware that I can make my own Ilist of the CustomOptionMetaDataCollection, however I would (with my mind on the rest of the code) list to use something simulair with more advanced collection classes.
I am also wondering how I would than map the OptionMetaDataCollection object to my CustomOptionMetadataCollection. I can create a loop but I am looking for a more effecient way to do the mapping.
Any help is much appreciated.
If you want to convert an IList<OptionMetadata> to a IList<CustomOptionMetadata>, you're effectively asking; How can I convert my base class (OptionMetadata) to a derived class (CustomOptionMetadata)?
Let's take the IList out of the equation for the moment - after all its just holding multiple copies of the class.
At it simplest level you basically want to do:
OptionMetadata optionMetadata = new OptionMetadata();
CustomOptionMetadata customOptionMetadata = (CustomOptionMetadata)optionMetadata;
Unfortunately this type of downcasting isnt really something C# does.
As Adam Wright describes in A way of casting a base type to a derived type.
This is downcasting, and there is no sane down way to handle it, . . . (subclasses provide more than base
classes - where does this "more" come from?)
So that said there are other ways to handle this, for example adding a constructor to your custom class which takes the base class.
class OptionMetadata
{
public int X;
}
class CustomOptionMetadata : OptionMetadata
{
public int Y;
public CustomOptionMetadata(OptionMetadata metadata)
{
this.Y = metadata.X * 2;
}
}
Then at its simplest it becomes:
OptionMetadata optionMetadata = new OptionMetadata();
CustomOptionMetadata customOptionMetadata = new CustomOptionMetadata(optionMetadata);
And to put the IList back into context.
IList<OptionMetadata> optionMetadata = new List<OptionMetadata>()
{
new OptionMetadata(),
new OptionMetadata()
};
IList<CustomOptionMetadata> customOptionMetadata = optionMetadata
.Select<OptionMetadata, CustomOptionMetadata>(metadata => new CustomOptionMetadata(metadata)).ToList();
I'm not really sure what you mean by 'mapping' one collection to another, but its sounds a bit like the same problem where you are trying to downcast a base class to a derived class. It not clear from your question what you are trying to achieve (what is the derived class actually doing?). If you just want to copy the contents of one collection to another I would suggest having a look at How do I copy items from list to list without foreach?.
I've got a question about getting the values from a constructor in a generic way.
namespace myTestNamespace
{
Public Class myTestClass()
{
Public myTestClass(int myInt,bool myBool, double myDouble)
{
//do / set something
}
Public myTestClass(int myInt,bool myBool)
{
//do / set something
}
}
}
Using (what you need);
Using myTestNamespace;
namespace MyIWannaLookForTheParametersName
{
Public Class MyLookUpClass()
{
Public void DoSomething()
{
List<object> myList = new List<object>();
myTestClass _ myTestClass = new myTestClass(1,true,2.5);
object mySaveObject = myTestClass;
mylist.Add(mySaveObject);
//how do I get the info from the right constructor
//(I used the one with 3 parameters_
//what was the value of myInt, myBool and myDouble
//how can I make it generic enough, so it will work with other classes with
// different constructors ass well?
}
}
}
Questions about intent aside, there's no generic way for you to do this. Information about what methods have been called and what values were supplied is not saved automatically. You are, of course, perfectly able to keep track of these things yourself, but you would have to write each class to do this explicitly.
Doing this in a generic way is asking for trouble. What if I did this?
public class Foo
{
public string Name { get; set; }
}
public class Bar
{
public Bar(Foo foo)
{
// ...
}
}
Then suppose I called it in this way:
Foo f = new Foo();
f.Name = "Jim";
Bar b = new Bar(f);
f.Name = "Bob";
Now, if such a generic system existed, what would be the value of foo for the Bar constructor? Either it reports "Bob" (which is what the value for Name is on the instance of Foo that was supplied), or it reports "Jim", meaning that the runtime or library would essentially have to be smart enough to make a deep copy of the object so that the state is not changed.
The bottom line is this: if you need access to the parameters passed to the constructor (or any other function), you'll have to store them somewhere explicitly.
You can't get thevalues from the constructor. You need to first place them in a property or a field within your class. The example you provided is a poor use of generics. You wouldbe better off placing the constructor values into properties and creating an interface with those properties.
I got what I needed with this method:
private static ParameterSettings[] GetListOfParametersFromIndicator(object indicatorClass, int loopId, myEnums.ParaOrResult paraOrResult)
{
return (from prop in indicatorClass.GetType().GetProperties()
let loopID = loopId
let Indicator = indicatorClass.GetType().Name
let value = (object)prop.GetValue(indicatorClass, null)
where prop.Name.Contains("_Constr_")
select new ParameterSettings { ParaOrResult=paraOrResult, LoopID= loopId, Indicator= Indicator, ParaName= prop.Name, Value= value }).ToArray();
}
where ParameterSettings is:
public struct ParameterSettings
{
public myEnums.ParaOrResult ParaOrResult { get; set; }
public int LoopID { get; set; }
public string Indicator { get; set; }
public string ParaName { get; set; }
public object Value { get; set; }
}
This info is ok for me. Thanks for the replies.
Regards,
Matthijs