Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 months ago.
Improve this question
class IntComponent
{
public int size;
}
class IntReferenceComponent : IntComponent
{
public IntComponent target; // keep my size same as target size
private void OnValidate()
{
//triggered on target assignment
}
}
Is it possible in C# make struct variable pointing to different struct variable like with objects ? Even with unsafe pointers ?
Edit
The final solution according to Charlieface solution:
public abstract class StructComponent<T> where T : struct
{
public T size;
}
public class IntComponent : StructComponent<int>{ }
public class IntReferenceComponent : IntComponent
{
public IntComponent target;
public new int size
{
get => target.size;
set => target.size = value;
}
}
In Unity I had to create custom editor:
public abstract class StructComponentEditor<T, D> : Editor where T : struct where D : StructComponent<T>
{
public static object StructField(string label, T value, params GUILayoutOption[] options)
{
switch (value)
{
case Vector3 v:
return EditorGUILayout.Vector3Field(label, v, options);
case Vector2 v:
return EditorGUILayout.Vector2Field(label, v, options);
case float f:
return EditorGUILayout.FloatField(label, f, options);
case int i:
return EditorGUILayout.IntField(label, i, options);
case double d:
return EditorGUILayout.DoubleField(label, d, options);
case Color c:
return EditorGUILayout.ColorField(label, c, options);
}
return null;
}
public void DrawDefaultStructComponent()
{
D target = serializedObject.targetObject as D;
PropertyInfo sizeProp = target.GetType().GetProperty("size");
object value;
try
{
value = sizeProp.GetValue(target);
}
catch
{
value = new T();
}
if(sizeProp.SetMethod != null)
{
sizeProp.SetValue(target, StructField("Size", (T)value));
return;
}
StructField("Size", (T)value);
}
public override void OnInspectorGUI()
{
DrawDefaultStructComponent();
DrawDefaultInspector();
}
}
[CustomEditor(typeof(StructComponent<int>), true)]
[CanEditMultipleObjects]
public class IntComponentEditor : StructComponentEditor<int, StructComponent<int>> { }
I need to write something because most of it is just code :)))))) So thanks to everyone who helped :) I love you <3
You don't need to do this in your case, and generally it would be ill-advised to try and mess around with pointers in normal Object Oriented cases, as you don't normally expose the internals of a class.
Instead, just use composition, with an outer property exposing the value of the inner object
class IntReferenceComponent : IntComponent
{
public IntComponent target; // keep my size same as target size
public int Size
{
get => target.size;
set => target.size = value;
}
}
You Can not do this with struct since its value type means you only can take a copy from it and you can't use it as a pointer as you do with classes
Below Code shows that even with pointers unsafe code will not work because you, in the end, will copy the values to a struct to use them,
since you can't access the object attribute with the pointer that
just `point to the object itself (this is what I know )
namespace Feto
{
internal struct Complex
{
public float real;
public float imag;
public Complex(float real, float image)
{
this.real = real;
this.imag = image;
}
public override string ToString()
{
return $" Class Complex {this.real} , {this.imag}";
}
}
class FixingComplex
{
public float real;
public float imag;
public FixingComplex(float real, float image)
{
this.real = real;
this.imag = image;
}
public override string ToString()
{
return $" Class Complex {this.real} , {this.imag}";
}
}
unsafe class program
{
public static void Main()
{
Complex x = new Complex(10, 20);
Console.WriteLine(x);
Complex* y = &x;
//address of stuct
Console.WriteLine((int)&x);
//the y point to it
Console.WriteLine((int)y);
//what z point to
Console.WriteLine(*y);
//send the addresss of the stuct
addNumbers(y);
Console.WriteLine(x);
Console.ReadKey();
void addNumbers(Complex* result)
{
//make sure it is the same address of stuct
Console.WriteLine((int)result);
//now here we got the address of struct we need to modify it
Console.WriteLine(*result);
//Here is the problem it will take copy
var value = *result;
value.real = 8888;
value.imag = 8888;
//you can use fixedcomplex to go on with pointers and workaround
.....
}
}
}
}
But there is a Solution
with small modifications like passing the address as a reference, not a copy of the address this will workaround and change the values and
The Changes addNumbers(ref y); void addNumbers(ref Complex* result) *result = new Complex(8888,8888);
namespace Feto
{
internal struct Complex
{
public float real;
public float imag;
public Complex(float real, float image)
{
this.real = real;
this.imag = image;
}
public override string ToString()
{
return $" Class Complex {this.real} , {this.imag}";
}
}
class FixingComplex
{
public float real;
public float imag;
public FixingComplex(float real, float image)
{
this.real = real;
this.imag = image;
}
public override string ToString()
{
return $" Class Complex {this.real} , {this.imag}";
}
}
unsafe class program
{
public static void Main()
{
Complex x = new Complex(10, 20);
Console.WriteLine(x);
Complex* y = &x;
//address of stuct
Console.WriteLine((int)&x);
//the y point to it
Console.WriteLine((int)y);
//what z point to
Console.WriteLine(*y);
//send the addresss of the stuct
addNumbers(ref y);
Console.WriteLine(x);
Console.ReadKey();
void addNumbers(ref Complex* result)
{
//make sure it is the same address of stuct
Console.WriteLine((int)result);
//now here we got the address of struct we need to modify it
Console.WriteLine(*result);
//Here is the problem it will take copy
//var value = *result;
*result = new Complex(8888,8888);
//you can use fixedcomplex to go on with pointers and workaround
}
}
}
}
Related
I have two constructors which feed values to readonly fields.
public class Sample
{
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
_intField = i;
}
public Sample(int theInt) => _intField = theInt;
public int IntProperty => _intField;
private readonly int _intField;
}
One constructor receives the values directly, and the other does some calculation and obtains the values, then sets the fields.
Now here's the catch:
I don't want to duplicate the
setting code. In this case, just one
field is set but of course there may
well be more than one.
To make the fields readonly, I need
to set them from the constructor, so
I can't "extract" the shared code to
a utility function.
I don't know how to call one
constructor from another.
Any ideas?
Like this:
public Sample(string str) : this(int.Parse(str)) { }
If what you want can't be achieved satisfactorily without having the initialization in its own method (e.g. because you want to do too much before the initialization code, or wrap it in a try-finally, or whatever) you can have any or all constructors pass the readonly variables by reference to an initialization routine, which will then be able to manipulate them at will.
public class Sample
{
private readonly int _intField;
public int IntProperty => _intField;
private void setupStuff(ref int intField, int newValue) => intField = newValue;
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
setupStuff(ref _intField,i);
}
public Sample(int theInt) => setupStuff(ref _intField, theInt);
}
Before the body of the constructor, use either:
: base (parameters)
: this (parameters)
Example:
public class People: User
{
public People (int EmpID) : base (EmpID)
{
// Add more statements here.
}
}
I am improving upon supercat's answer. I guess the following can also be done:
class Sample
{
private readonly int _intField;
public int IntProperty
{
get { return _intField; }
}
void setupStuff(ref int intField, int newValue)
{
//Do some stuff here based upon the necessary initialized variables.
intField = newValue;
}
public Sample(string theIntAsString, bool? doStuff = true)
{
//Initialization of some necessary variables.
//==========================================
int i = int.Parse(theIntAsString);
// ................
// .......................
//==========================================
if (!doStuff.HasValue || doStuff.Value == true)
setupStuff(ref _intField,i);
}
public Sample(int theInt): this(theInt, false) //"false" param to avoid setupStuff() being called two times
{
setupStuff(ref _intField, theInt);
}
}
Here is an example that calls another constructor, then checks on the property it has set.
public SomeClass(int i)
{
I = i;
}
public SomeClass(SomeOtherClass soc)
: this(soc.J)
{
if (I==0)
{
I = DoSomethingHere();
}
}
Yeah, you can call other method before of the call base or this!
public class MyException : Exception
{
public MyException(int number) : base(ConvertToString(number))
{
}
private static string ConvertToString(int number)
{
return number.toString()
}
}
Constructor chaining i.e you can use "Base" for Is a relationship and "This" you can use for same class, when you want call multiple Constructor in single call.
class BaseClass
{
public BaseClass():this(10)
{
}
public BaseClass(int val)
{
}
}
class Program
{
static void Main(string[] args)
{
new BaseClass();
ReadLine();
}
}
When you inherit a class from a base class, you can invoke the base class constructor by instantiating the derived class
class sample
{
public int x;
public sample(int value)
{
x = value;
}
}
class der : sample
{
public int a;
public int b;
public der(int value1,int value2) : base(50)
{
a = value1;
b = value2;
}
}
class run
{
public static void Main(string[] args)
{
der obj = new der(10,20);
System.Console.WriteLine(obj.x);
System.Console.WriteLine(obj.a);
System.Console.WriteLine(obj.b);
}
}
Output of the sample program is
50 10 20
You can also use this keyword to invoke a constructor from another constructor
class sample
{
public int x;
public sample(int value)
{
x = value;
}
public sample(sample obj) : this(obj.x)
{
}
}
class run
{
public static void Main(string[] args)
{
sample s = new sample(20);
sample ss = new sample(s);
System.Console.WriteLine(ss.x);
}
}
The output of this sample program is
20
Error handling and making your code reusable is key. I added string to int validation and it is possible to add other types if needed. Solving this problem with a more reusable solution could be this:
public class Sample
{
public Sample(object inputToInt)
{
_intField = objectToInt(inputToInt);
}
public int IntProperty => _intField;
private readonly int _intField;
}
public static int objectToInt(object inputToInt)
{
switch (inputToInt)
{
case int inputInt:
return inputInt;
break;
case string inputString:
if (!int.TryParse(inputString, out int parsedInt))
{
throw new InvalidParameterException($"The input {inputString} could not be parsed to int");
}
return parsedInt;
default:
throw new InvalidParameterException($"Constructor do not support {inputToInt.GetType().Name}");
break;
}
}
Please, please, and pretty please do not try this at home, or work, or anywhere really.
This is a way solve to a very very specific problem, and I hope you will not have that.
I'm posting this since it is technically an answer, and another perspective to look at it.
I repeat, do not use it under any condition. Code is to run with LINQPad.
void Main()
{
(new A(1)).Dump();
(new B(2, -1)).Dump();
var b2 = new B(2, -1);
b2.Increment();
b2.Dump();
}
class A
{
public readonly int I = 0;
public A(int i)
{
I = i;
}
}
class B: A
{
public int J;
public B(int i, int j): base(i)
{
J = j;
}
public B(int i, bool wtf): base(i)
{
}
public void Increment()
{
int i = I + 1;
var t = typeof(B).BaseType;
var ctor = t.GetConstructors().First();
ctor.Invoke(this, new object[] { i });
}
}
Since constructor is a method, you can call it with reflection. Now you either think with portals, or visualize a picture of a can of worms. sorry about this.
In my case, I had a main constructor that used an OracleDataReader as an argument, but I wanted to use different query to create the instance:
I had this code:
public Subscriber(OracleDataReader contractReader)
{
this.contract = Convert.ToString(contractReader["contract"]);
this.customerGroup = Convert.ToString(contractReader["customerGroup"]);
this.subGroup = Convert.ToString(contractReader["customerSubGroup"]);
this.pricingPlan= Convert.ToString(contractReader["pricingPlan"]);
this.items = new Dictionary<string, Member>();
this.status = 0;
}
So I created the following constructor:
public Subscriber(string contract, string customerGroup) : this(getSubReader(contract, customerGroup))
{ }
and this method:
private static OracleDataReader getSubReader(string contract, string customerGroup)
{
cmdSubscriber.Parameters[":contract"].Value = contract + "%";
cmdSubscriber.Parameters[":customerGroup"].Value = customerGroup+ "%";
return cmdSubscriber.ExecuteReader();
}
notes: a statically defined cmdSubscriber is defined elsewhere in the code; My main constructor has been simplified for this illustration.
In case you need to run something before calling another constructor not after.
public class Sample
{
static int preprocess(string theIntAsString)
{
return preprocess(int.Parse(theIntAsString));
}
static int preprocess(int theIntNeedRounding)
{
return theIntNeedRounding/100;
}
public Sample(string theIntAsString)
{
_intField = preprocess(theIntAsString)
}
public Sample(int theIntNeedRounding)
{
_intField = preprocess(theIntNeedRounding)
}
public int IntProperty => _intField;
private readonly int _intField;
}
And ValueTuple can be very helpful if you need to set more than one field.
NOTE: most of the solutions above does not work for structs.
Unfortunately initializing struct fields in a method called by a constructor is not recognized by the compiler and will lead to 2 errors:
in the constructor: Field xxxx must be fully assigned...
in the method, if you have readonly fields: a read-only field cannot be assigned except in a constructor.
These can be really frustrating for example when you just need to do simple check to decide on which constructor to orient your call to.
I'm trying to implement a script evaluator to evaluate some classes that my users will implement that will have a fixed entry point accepting a variable that will be given from the main application.
To do this I've declared a namespace that contains the type of the object that will be passed to the entry point. This is the whole code that declares the custom type and executes the scripts:
namespace MyNamespace
{
public class Vertex
{
public float X { get; } = 0.0f;
public float Y { get; } = 0.0f;
public float Z { get; } = 0.0f;
public Vertex(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
public override string ToString()
{
return string.Format("[{0}, {1}, {2}]", X, Y, Z);
}
}
}
public class Globals
{
public Vertex testVertex = new Vertex(0, 0, 0);
public int testValue = 100;
}
class Program
{
static void Main(string[] args)
{
try
{
ScriptOptions options = ScriptOptions.Default;
// Add assemblies
options = options.AddReferences(
typeof(System.Object).GetTypeInfo().Assembly,
typeof(System.Linq.Enumerable).GetTypeInfo().Assembly,
typeof(MyNamespace.Vertex).GetTypeInfo().Assembly
);
// Add usings
options = options.AddImports("System");
options = options.AddImports("System.Linq");
options = options.AddImports("System.Collections.Generic");
options = options.AddImports("MyNamespace");
var script = <added below>;
Globals globals = new Globals();
ScriptState<object> scriptState = CSharpScript.RunAsync(script, options: options, globals: globals).Result;
scriptState = scriptState.ContinueWithAsync(#"Figure fig = new Figure();").Result;
scriptState = scriptState.ContinueWithAsync(#"fig.Draw(testVertex);").Result;
}
catch (CompilationErrorException e)
{
Console.WriteLine(string.Join(Environment.NewLine, e.Diagnostics));
}
}
}
And this is an example of a script that I'm trying to load:
public class Figure
{
public void Draw(Vertex v)
{
System.Console.WriteLine(v.ToString());
}
public void Draw(int i)
{
System.Console.WriteLine(i);
}
}
Now, the problem is that when I call the method Draw of the class Figure inside the script, it throws me an exception saying
error CS1503: Argument 1: cannot convert from 'MyNamespace.Vertex [~/Projects/ScriptTest/ScriptTest/bin/Debug/netcoreapp1.0/ScriptTest.dll]' to 'MyNamespace.Vertex [ScriptTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]'
When I do
scriptState = scriptState.ContinueWithAsync(#"fig.Draw(testValue);").Result; // Using testValue instead of testVertex
everything works fine.
It think the problem is that the script is referring to a different namespace than MyNamespace but I don't know how to solve this.
I am creating a linear algebra library in C#, and I would like to force dimension inconsistency errors up to compile-time. I've implemented a similar solution to this, where the trait I use is a class that uniquely maps to an integer. The problem is for every possible size I would like my Vectors to have, I would need to create a class with a unique name to represent it.
Here is an example of that implementation:
public class Vector<T> where T: ISize, new()
{
static readonly T size = new T();
List<double> values;
public Vector(List<double> values)
{
if (values.Count != size.Size)
throw new IndexOutOfRangeException();
this.values = new List<double>(values);
}
public double Get(int index)
{
return values[index];
}
public Vector<T> Add(Vector<T> other)
{
var vv = new List<double>();
for (int ii = 0; ii < size.Size; ++ii)
vv.Add(other.Get(ii) + this.values[ii]);
return new Vector<T>(vv);
}
}
public interface ISize
{
int Size { get; }
}
public class S1 : ISize
{
public int Size
{
get { return 1; }
}
}
public class S2 : ISize
{
public int Size
{
get { return 2; }
}
}
And here's an example of its usage:
class Program
{
static void Main(string[] args)
{
var v1 = new Vector<S2>(new List<double>() { 1, 2 });
var v2 = new Vector<S2>(new List<double>() { 10, -4 });
var z1 = new Vector<S1>(new List<double>() { 10 });
// works
var v3 = v1.Add(v2);
// complie-time error
var z2 = z1.Add(v1);
}
}
This works quite well for my purposes, except for the fact that I would need to create a different implementation of ISize for every possible Vector size. Is there any way for me to implement the Vector class that would allow me to get around this problem?
In order to get a compile-time error, you need to have different types. C# does not have a concept that let's you define a type parameter that itself takes a kind of value parameters - which is what you would need to do this.
Therefore, I don't think what you are asking is possible.
I think there might be a way to make unique types for family of vector instances using anonymous types, but that's going to be quirky and I don't think it would provide the type safety that you want.
C++ has such a concept in templates (so it's not unreasonable), just not possible in C#.
You can create a single N-dimentional Vector class with compile time type checking, but it's pretty messy. What we're creating here is LISP style linked-lists, but through generic type arguments rather than purely out of object references via fields.
public interface IVector
{
double Value { get; }
IVector Tail { get; }
}
public class Vector<T> : IVector
where T : IVector
{
internal Vector(double value, T tail)
{
Value = value;
Tail = tail;
}
public double Value { get; private set; }
public T Tail { get; private set; }
public Vector<Vector<T>> Add(double value)
{
return new Vector<Vector<T>>(value, this);
}
}
internal class EmptyVector : IVector
{
public double Value
{
get { throw new NotImplementedException(); }
}
public IVector Tail
{
get { return null; }
}
}
public static class Vector
{
public static readonly Vector<IVector> Empty = new Vector<IVector>(
0, new EmptyVector());
public static IEnumerable<double> AllValues(this IVector vector)
{
IVector current = vector;
while (current != Vector.Empty && current != null)
{
yield return current.Value;
current = current.Tail;
};
}
}
This allows us to write:
var v1 = Vector.Empty.Add(1).Add(2);
var v2 = Vector.Empty.Add(10).Add(-4);
var z1 = Vector.Empty.Add(10);
v1 = v2;//works, as they are the same type
z1 = v2;//fails, as they aren't the same type, since they're a different size
This allows allows you to write a method that accepts a vector of a particular size. It's not convenient, and it doesn't scale, but it works. If you want, say, a 3D vector as a parameter, you can write:
public static void Foo(Vector<Vector<Vector<IVector>>> vector)
{
var first = vector.Value;
var second = vector.Tail.Value;
var third = vector.Tail.Tail.Value;
}
I have a 3D array that I'm accessing this way Array(int x, int y, int z). What I would like to know, if it is possible to have a struct, that has xyz in it, so that I can use it this way: Array(struct xyz). If it is, then how?
The reason for why I would want this, is that it would be easier for me to read and write, and that it would be alot simpler and less error prone to write. Makes it easier to maintain the bigger picture.
I do know that I could make a class that has its own method, but since I have many classes and applying it to each one would make me quickly loose the readability, using the struct directly would be a better option if available.
Example:
public struct xyz
{
public int x, y, z;
public xyz(int X, int Y, int Z)
{
x = X;
y = Y;
z = Z;
}
}
private void Test()
{
int(,,) Array = new int()
{
{
{0,0},
{0,0},
},
{
{0,0},
{0,0},
}
};
xyz XYZ = new xyz(0,0,0);
Array[XYZ] = 1; // this instead of
Array[XYZ.x, XYZ.y, XYZ.z] = 1 // this
}
You could create your own array class that wraps a real array, and provides an indexer to do what you want:
class MyArray<T>
{
private T[,,] array;
public MyArray(int xSize, int ySize, int zSize)
{
array = new T[xSize,ySize,zSize];
}
public T this[XYZ xyz]
{
get { return array[xyz.x, xyz.y, xyz.z]; }
set { array[xyz.x, xyz.y, xyz.z] = value; }
}
}
You can easily achieve that by creating your own collection that can be accessed either by specifying all thee coordinates separately:
public T this[int x, int y, int z] { get { … } set { … } }
Or by your XYZ struct:
public T this[XYZ xyz] { get { … } set { … } }
You can't add that indexer to array, extension indexers are not possible. What you could do is to create two extension methods. Something like:
public static T Get<T>(this T[,,] array, XYZ xyz)
{
return array[xyz.X, xyz.Y, xyz.Z];
}
public static void Set<T>(this T[,,] array, XYZ xyz, T value)
{
array[xyz.X, xyz.Y, xyz.Z] = value;
}
And then use it like this:
int i = array.Get(xyz);
array.Set(xyz, 25);
Also, creating mutable structs, like you did, is considered worst practice in C#. They can be very confusing.
Completing the solution of #Andrew Cooper, if you also want to access that matrix normally you must add this methods (Look at the end of Andrew's code)
class MyArray<T>
{
private T[,,] array;
// Constructor
public MyArray(int xSize, int ySize, int zSize)
{
array = new T[xSize,ySize,zSize];
}
// Index with your own struct XYZ
public T this[XYZ xyz]
{
get { return array[xyz.x, xyz.y, xyz.z]; }
set { array[xyz.x, xyz.y, xyz.z] = value; }
}
// Normal index
public T this[int x, int y , int z]
{
get { return array[x, y, z]; }
set { array[x, y, z] = value; }
}
// Get dimensions
public int GetLength(int dim)
{
return array.GetLength(dim);
}
}
I'm not at all new to programming, but there seems to be a hole in my understanding of C# structs.
Can anyone explain why the following code prints out the following?
Dist1: 0, Dist2: 0
struct Distance
{
public void SetFeet(int feet) { Value = feet; }
public void SetMiles(float miles) { Value = (int)(miles * 5280f); }
public int GetFeet() { return Value; }
public float GetMiles() { return Value / 5280f; }
private int Value;
}
class Distances
{
public Distance Dist1 { get; set; }
public Distance Dist2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
Distances distances = new Distances();
distances.Dist1.SetFeet(1000);
distances.Dist2.SetFeet(2000);
Console.WriteLine("Dist1: {0}, Dist2: {1}",
distances.Dist1.GetMiles(),
distances.Dist2.GetMiles());
Console.ReadLine();
}
}
Getters and setters -- how properties are accessed -- still function like methods in this regard. That is,
distances.Dist1.SetFeet(1000);
is "equivalent" to
distances.GetDist1().SetFeet(1000);
The "copy" of the structure (value) is made when it is returned from the getter (or passed to the setter). If Dist1 were a member variable this would not be the case and would work "as expected".
Happy coding.
struct are value types - so when you are accessing distances.Dist1.SetFeet you basically are accessing a copy... see for example at MSDN http://msdn.microsoft.com/en-us/library/aa288471%28v=vs.71%29.aspx
[EDIT after comment]
On the other hand, if you do distances.Dist1 = new Distance ().SetFeet (1000); AND change the return of SetFeet from void to Distance it should work. Alternatively make Distance a class.
For a reference on how to build structs in a way that they work as expected see the DateTime struct in the framework - http://msdn.microsoft.com/en-us/library/system.datetime.aspx
[/EDIT after comment]
Properties are treated differently to variables, just remove { get; set; } from your Distance declaration and the code works fine.
struct Distance
{
public void SetFeet(int feet) { Value = feet; }
public void SetMiles(float miles) { Value = (int)(miles * 5280f); }
public int GetFeet() { return Value; }
public float GetMiles() { return Value / 5280f; }
private int Value;
}
class Distances
{
public Distance Dist1;//here
public Distance Dist2;//and here
}
class Program
{
static void Main(string[] args)
{
Distances distances = new Distances();
distances.Dist1.SetFeet(1000);
distances.Dist2.SetFeet(2000);
Console.WriteLine("Dist1: {0}, Dist2: {1}", distances.Dist1.GetMiles(),
distances.Dist2.GetMiles());
Console.ReadLine();
}
}