In this question I would like to find out if and how this is possible. This technique would seem extremely bad practice but it seems that the API (UnityEditor) that I am using, is doing something like this and I am just curious.
If there are multiple references to the same object, is it possible to instantiate a new object into the same memory slot so that all previous references point to the new object?
I figured out that the only feasible way to do so is by using unmanaged C++. Essentially the following is happening:
// Original prefab
GameObject prefab = x;
prefab.tag = "Untagged";
// A copy of the original prefab
GameObject prefabCopy = PrefabUtility.InstantiatePrefab(prefab) as GameObject;
prefabCopy.tag = "EditorOnly"; // Change from initial value "Untagged"
Debug.Log(prefab.tag); // "Untagged" - expected
Debug.Log(prefabCopy.tag); // "EditorOnly" - expected
// Replace contents of prefab file with `prefabCopy`
PrefabUtility.ReplacePrefab(prefabCopy, prefab);
// Destroy the copy
DestroyImmediate(prefabCopy);
Debug.Log(prefab.tag); // "EditorOnly" - whoa?
Some how prefab is now pointing to a different object?
Note: Bear in mind that Unity is built on top of the Mono flavour of .NET
Since an object state is defined by field values, you can copy memory, containing field values, from one object to another, effectively "replacing" it:
public static void Replace<T>(T x, T y)
where T : class
{
// replaces 'x' with 'y'
if(x == null) throw new ArgumentNullException("x");
if(y == null) throw new ArgumentNullException("y");
var size = Marshal.SizeOf(typeof(T));
var ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(y, ptr, false);
Marshal.PtrToStructure(ptr, x);
Marshal.FreeHGlobal(ptr);
}
Note that this code requires [StructLayout(LayoutKind.Sequential)] (or LayoutKind.Explicit) attribute defined for a class.
You could do that if you embed your object into another one that is used to access the object.
class ObjectReference<T>
where T : new()
{
private T _obj = new T();
public void CreateNewObject()
{
_obj = new T();
}
public T Value { get return _obj; }
}
Now you can create multiple references to an object of type ObjectReference and only change the local object. The "real" object would be accessed through the Value property
A slightly different approach is that you create a wrapper that implements the same interface as your "real" object, thus making this wrapping transparent.
interface ISomeInterface
{
string PropertyA { get; set }
void MethodB (int x);
}
class TheRealObject : ISomeInterface
{
public string PropertyA { get; set }
public void MethodB (int x)
{
Console.WriteLine(x);
}
}
class Wrapper : ISomeInterface
{
TheRealObject _obj = new TheRealObject();
public string PropertyA
{
get { return _obj.PropertyA; }
set { _obj.PropertyA = value; }
}
public void MethodB (int x)
{
_obj.MethodB(x);
}
public void CreateNewObject()
{
_obj = new TheRealObject();
}
}
Now the wrapper can be used as if it was the "real" object. You could also pass an initial instance of the "real" object in the wrapper's constructor and remove the initializer of _obj.
No, that's not possible.
To actually change all references to an object, you would have to freeze all threads in the process, and access their register sets and stack. That's what the garbage collector does, but it's not possible for regular code.
What the method most likely does is to make a deep copy of one object onto the other.
If it is a custom Class you want to reference, i think you can have all the references point to a Fake Reference...
create your class (A)
create your class Interface (IA)
Create a wrapper class based on your interface which just passes all calls to a contained object (AC)
I Added a Assignment operator so i have all A Objects as ACs.
class AC:IA
{
IA ref;
AC(IA ref)
{
this.ref = ref;
}
public void ChangeReference(IA newRef) { ref = newRef;}
public static operator = (IA assignedObj)
{
return (assignedObject is AC) ? assignedObject : new AC(assignedObj);
}
// implementation of all methods in A
public override string ToString() { return ref.ToString(); }
...
}
Now if you want, you can use the ChangeReference method to switch all to the new Reference..
in C++ you would use Reference to Reference
Best of luck
Related
Okay so I made a class to take an input script and a property name. It finds the property and then displays it when Display() is called [The display method is overridden by a child class]. However, there is one problem that I have with it and that is how do I cache what FieldInfo.GetValue() returns? It would be preferable to have a pointer or something to reuse once the variable containing what I need is found since reflection is costly.
public class PropertyDisplayer : MonoBehaviour
{
public string PropertyName;
public Object TargetObject;
public object _TargetObject;
public FieldInfo Property;
void Start()
{
_TargetObject = TargetObject;
if (!PropertyName.Contains("."))
{
Property = _TargetObject.GetType().GetField(PropertyName);
}
else
{
string[] split = PropertyName.Split('.');
Property = _TargetObject.GetType().GetField(split[0]);
for (int i = 1; i != split.Length; i++)
{
_TargetObject = Property.GetValue(_TargetObject);
Property = Property.FieldType.GetField(split[i]);
}
}
}
public virtual void Display()
{
}
}
Use the dynamitey library, it will cache all reflection calls transparently for you and make them near normal call speed. More info here: https://github.com/ekonbenefits/dynamitey
You can store the results of the FieldInfo.GetValue() call in a new member field that is of type "object". (This IS, effectively, a pointer)
Then, in your Display() override, simply cast this member to the appropriate class, in order to access its members.
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'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...
I have a .NET COM object, that i uses to call from C code.
[EventTrackingEnabled(true)]
[ComVisible(true)]
public class ComObject : IComObject
{
private static XslCompiledTransform transformer = null;
private static string transformerXsltPath = null;
private static string TransformerXsltPath
{
get
{
return transformerXsltPath;
}
set
{
transformerXsltPath = value;
}
}
private static XslCompiledTransform Transformer
{
get
{
return transformer;
}
set
{
transformer = value;
}
}
[ComVisible(true)]
public bool TransformXML(String inputPath, String xsltPath, String outputPath)
{
// ....
if (Transformer == null || xsltPath != TransformerXsltPath)
{
Transformer = new XslCompiledTransform(true);
Transformer.Load(xsltPath, new XsltSettings(true, true), new XmlUrlResolver());
}
// ...
}
}
I want to keep the state of the com object, as long as i call this method. by static members. so when i'll call it again, the state members will be initialized.
But the problem is, that just the Transformer object stay initialized in the second call but the transformerXsltPath string restarted to null.
how it is possible ?
First, a field doesn't need to be static in order to retain its value between method calls (only variables declared inside methods have that property). Static means that the field belongs to the class, not to any instance of the class, and there is only one instance of the field, which is shared by all instances of the class (and can even be accessed without creating an instance of the class, as in Class.field). For more information see fields and static fields.
Second, I don't see how you expect the transformerXsltPath field to be modified when you don't modify it anywhere (and it's private, which means that it can't be modified outside the class).
Say I have a struct declared like the following:
public struct Test
{
public static int Width = 5;
...
public static int[] Value = new int[1]{ 0 };
}
Now what I want to do is call this from within another struct, but I have to clue how. What I'm trying to do would (in my mind) look like the following:
public struct AnotherStruct
{
public (type of struct) this[int key]
{
get
{
switch(key)
{
case 1:
return (another struct);
default:
return null;
}
}
}
}
My end goal is that I want to use code that looks like the following, without having to create an instance of the object:
structobject s = new AnotherStruct[5];
So this 'lookup table' will be created in another project and built, then called as a dll from my main project. Since I'm building the dll elsewhere and calling it, I'm hoping that I can get the dll loaded into memory once, and then I can just reference that memory from my main project. Then I'll have one allocated portion of memory and my code will just reference it, avoiding the need to create individual instances of this lookup table (thus avoiding the time overhead it takes to allocate the memory and store the new instance). The time I'd save would be hugely beneficial in the long run, so I'm hoping I can get this to work somehow.
I hope this isn't too confusing, but let me know if any clarification is needed.
Edit
This is being used on a website, so really I need an object that persists across all connections and is created once when the code is initially loaded. Same idea, but maybe that will make for a simpler solution?
Solution #2. Forgo the whole ID idea and just use the structure type and generics.
public struct St1
{
}
public struct St2
{
}
public class Factory<T>
where T : struct
{
static T _new = new T(); //cached copy of structure
public static T New { get { return _new; } }
}
class Program
{
static void Main(string[] args)
{
St1 x1 = Factory<St1>.New;
St1 x2 = Factory<St1>.New;
St1 x3 = Factory<St1>.New;
St2 y1 = Factory<St2>.New;
St2 y2 = Factory<St2>.New;
}
}
Solution #1. Using a common interface for all the structures and a dictionary collection
public interface IStr { }
public struct St1 : IStr
{
public static int ID = 1;
}
public struct St2 : IStr
{
public static int ID = 2;
}
public class StructFactory : System.Collections.ObjectModel.KeyedCollection<int, IStr>
{
public static StructFactory Default = new StructFactory();
protected override int GetKeyForItem(IStr item)
{
FieldInfo finfo = item.GetType().GetField("ID",
BindingFlags.Static | BindingFlags.Public);
return (int)finfo.GetValue(item);
}
public StructFactory()
{
Add(new St1());
Add(new St2());
}
}
class Program
{
static void Main(string[] args)
{
St1 x = (St1)StructFactory.Default[1];
St2 y = (St2)StructFactory.Default[2];
}
}
The syntax you use above won't work since it means "create an array of AnotherStruct with five elements in it." As mentioned in a comment, however, you really should look into using a factory pattern.
However, if you really want to use the pattern above, you could change it up slightly. Have your AnotherStruct array hold Type instances of each of your structs. Then, your "creation" line would look more like:
structobject s = (structobject)Activator.CreateInstance(AnotherStruct[5]);
You can use reflection on the Assembly (since you are wrapping it in a DLL) to get those Type objects.
And finally, unless you have a really good reason for using struct (and understand all of the nuances, of which there are several), stick with class.