I have a custom class
class MyClassA{
public int Width { get; set; }
}
and another custom class B
class MyClassB {
public MyClassA paramClassA;
public int Height { get; set; }
}
Is there a way to have a constructor inside MyClassB which accepts a parameters of type MyClassB and automatically assigns values to the attribute?
Something like this:
class MyClassB{
public MyClassA paramClassA;
public int Height { get; set; }
public MyClassB(MyClassB param){
}
public MyClassB(MyClassB param){
// automatically assign properties of param to the instance it is created
}
}
So I can do this:
var classB = new MyClassB();
classB.Height = 100;
classB.paramClassA = new MyClassA();
classB.paramClassA.Width = 100;
var classB2 = new MyClassB(classB);
Is there a way to do this?
ThereĀ“s no in-built way to do this. Anyway this is the purpose of a copy-constructor and can be achieved by copying all the properties from your existing instance to the current one. However when you have a deep inheritance-chain copying all those members can be non-trivial task which also includes private members.
class MyClassB{
public MyClassA paramClassA;
public int Height { get; set; }
public MyClassB(MyClassB param){
this.Heigth = param.Height;
this.MyClassA = param.MyClassA;
}
}
You could also implement ICloneable:
class MyClassB : ICloneable {
public MyClassA paramClassA;
public int Height { get; set; }
public object Clone(){
return new MyClassB
{
this.Height;
this.MyClassA;
};
}
}
Yes, you can do it manually. Remember about differences between shallow copy and deep copy in C# language:
class MyClassB{
public MyClassA paramClassA;
public int Height { get; set; }
public MyClassB(MyClassB param){
Height = param.Height;
paramClassA = new MyClassA();
if (param.paramClassA != null)
{
paramClassA.Width = param.paramClassA.Width;
}
}
}
I'll recommend Clone method inside MyClassB class:
class MyClassB{
//....
public MyCLassB Clone()
{
var result = new MyClassB
{
Height = Height
};
result.paramClassA = new MyClassA();
if (paramClassA != null)
{
result.paramClassA.Width = paramClassA.Width;
}
}
}
And use it, like below:
var classB = new MyClassB();
classB.Height = 100;
classB.paramClassA = new MyClassA();
classB.paramClassA.Width = 100;
var classB2 = classB.Clone();
You could always create a copy method that would assign the values and return a MyClassB where you assign the values within. If you must do it in a constructor check out the following.
public MyClassB(MyClassB param)
{
Width = param.Width;
// If you want to keep the same reference classA
paramClassA = param.paramClassA;
// if you want the classA to not be the same reference you could always do.
paramClassA = new MyClassA() { Width = param.Width };
}
Related
I have two classes like below:
public async A GernerateStuff(int expireDays = 15)
{
using var randomNumberGenerator = RandomNumberGenerator.Create();
var randomBytes = new byte[64];
var now = DateTime.UtcNow;
randomNumberGenerator.GetBytes(randomBytes);
return new A
{
Stuff = Convert.ToBase64String(randomBytes),
Created = now,
Expires = now.AddDays(expireDays)
};
}
public async B GernerateStuff(int expireDays = 10)
{
using var randomNumberGenerator = RandomNumberGenerator.Create();
var randomBytes = new byte[64];
var now = DateTime.UtcNow;
randomNumberGenerator.GetBytes(randomBytes);
return new B
{
Stuff = Convert.ToBase64String(randomBytes),
Created = now,
Expires = now.AddDays(expireDays)
};
}
public class A
{
public string Stuff{ get; set; }
public DateTime Created { get; set; }
public DateTime Expires { get; set; }
}
public class B
{
public string Stuff{ get; set; }
public DateTime Created { get; set; }
public DateTime Expires { get; set; }
}
The constraint is: I can not create just one class instead of two separate classes A and B as they have significant differences in usage.
Now, my question is: how can I clean this code up having both classes A and B but a single method for GernerateStuff?
I can create an interface like this:
public class A : IInterface
{
}
public class B : IInterface
{
}
public interface IInterface
{
public string Stuff{ get; set; }
public DateTime Created { get; set; }
public DateTime Expires { get; set; }
}
Then, the problem is how public async IInterface GernerateStuff(int expireDays = 15) signature would handle both class A and B?
There are a couple of ways tot achieve this. One has already been mentioned in other answeres, which is about using generics. However this assumes your types A and B do even have anything in common that you could use as common generic constraint - e.g a common base-interface. Then you could do this:
public async T GernerateStuff<T>(int expireDays = 15) where T: new(), MyInterface
{
using var randomNumberGenerator = RandomNumberGenerator.Create();
var randomBytes = new byte[64];
var now = DateTime.UtcNow;
randomNumberGenerator.GetBytes(randomBytes);
return new T
{
Stuff = Convert.ToBase64String(randomBytes),
Created = now,
Expires = now.AddDays(expireDays)
};
}
You could also create a factory that creates the instances of A or B depending on some condition - e.g. some configuration. However you'd also need a common base-interface for that:
public async MyInterface GernerateStuff(int expireDays = 15)
{
using var randomNumberGenerator = RandomNumberGenerator.Create();
var randomBytes = new byte[64];
var now = DateTime.UtcNow;
randomNumberGenerator.GetBytes(randomBytes);
return CreateTheThing(Convert.ToBase64String(randomBytes), now, now.AddDays(expireDays));
}
MyInterface CreateTheThing(string stuff, DateTime created, DateTime expires)
{
if(...)
return new A { ... }
else if(...)
return new B { ... }
return new C { ... }
}
This solution has the advantage, that you don't need to change the client-logic when you add a new type to the factory. All you need to change is the factory itself by introducing new C { ... }. Furthermor a client cannot provide any types that actually don't work, as they don't provide any type-information at all.
By the way your method does not await anything, so there's no reason to make it async.
Create a static factory method and inject it as a parameter:
public static A CreateA(byte[] stuff, DateTime now, DateTime expires)
=> new A{ Stuff = stuff, Created = now, Expires = expires }
...
public static T GernerateStuff<T>(Func<byte[], DateTime, DateTime, T> ctor, int expireDays = 15)
{
using var randomNumberGenerator = RandomNumberGenerator.Create();
var randomBytes = new byte[64];
var now = DateTime.UtcNow;
randomNumberGenerator.GetBytes(randomBytes);
return ctor(
Convert.ToBase64String(randomBytes),
now,
now.AddDays(expireDays)
;
}
...
var a = GernerateStuff(CreateA);
But if class A and B are identical, why not use the same class? This is a definite code smell, and you should probably think about how you model your problem some more. Also, async does not serve any point without an await, so get rid of it.
I am little bit late at the party, however you can use dictionary with delegates which can provide lazy initialization.
Let me show an example. At first, we need to make enums to avoid if else statements while creating instances of classes:
public enum FooType
{
A, B
}
Then we need to have abstract base class which has the same behaviour for all derived classes:
public abstract class FooBase
{
public string? Stuff { get; set; }
public DateTime Created { get; set; }
public DateTime Expires { get; set; }
}
And derived classes look like this:
public class A : FooBase
{
public A(int expireDays)
{
}
public override string ToString() => $"I am A class";
}
public class B : FooBase
{
public B(int expireDays)
{
}
public override string ToString() => $"I am B class";
}
Then Factory looks like this and you can customize any property or method if you want to:
public class FooFactory
{
Dictionary<FooType, Func<FooBase>> _fooBaseByType;
public Func<FooBase> GetInstance(FooType fooType, int expireDays)
{
_fooBaseByType = new Dictionary<FooType, Func<FooBase>>
{
{
FooType.A, () => new A(expireDays)
{
Created = SomeCustomDateTime(),
Stuff = SomeCustomString()
}
},
{
FooType.B, () => new B(expireDays)
{
Created = SomeCustomDateTime()
}
}
};
return _fooBaseByType[fooType];
}
private DateTime SomeCustomDateTime() => DateTime.Now;
private string SomeCustomString() => "My custom string";
}
And you can use it like this:
FooFactory factory = new FooFactory();
A a = (A)factory.GetInstance(FooType.A, 11)();
I am creating a program in C# and I don't know how to create my classes.
Here's what my class looks like:
public class MyClass
{
public class Parameters
{
string Value { get; set;}
}
public class Methods
{
public void MyMethod()
{
Window.Title = Parameters.Value;
}
}
}
And this is how I want to be able to use it from another class:
public class MainClass
{
MyClass myclass = new MyClass();
myclass.Parameters.Value = "Hello World !";
myclass.Methods.MyMethod();
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass();
myclass2.Parameters.Value = "Hello World Again !";
myclass2.Methods.MyMethod();
//I know this code is stupid, it's just to simplify my example.
}
But it doesn't work, there are accessibility problems that I don't know how to solve.
Thanks in advance, I don't think that the solution is very complicated but I can't find it.
You need to make the Value property public to get or set it from outside the class:
public string Value { get; set; }
The classes are not static, so you need to instantiate them to set their properties or use their methods:
var parameters = new MyClass.Parameters();
parameters.Value = "Hello World !";
var methods = new MyClass.Methods();
methods.MyMethod();
The same applies here:
public void MyMethod()
{
var parameters = new MyClass.Parameters();
Window.Title = parameters.Value;
}
But I suspect you actually want MyClass to have its own instances of these classes. So you can add properties for them:
public Properties Properties { get; set; }
public Methods Methods { get; set; }
Then instantiate them somehow (like in the constructor):
public MyClass()
{
Parameters = new Parameters();
Methods = new Methods();
}
If you do steps 1, 4 and 5, the code you have in MainClass should work.
Create a constructor that force the user to add a Value when initiating the class
public class MyClass
{
public string Value { get; set; }
public MyClass(string value)
{
Value = value;
}
public class Methods
{
public void MyMethod()
{
Window.Title = Value;
}
}
}
and call it like this
MyClass myclass = new MyClass("Hello World !");
myclass.Methods.MyMethod();
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass("Hello World Again !");
myclass2.Methods.MyMethod();
You can declare the properties and methods all within the class:
public class MyClass
{
public MyClass()
{
// Set any initial values
}
public string Value { get; set;}
public void MyMethod()
{
Window.Title = Value;
}
}
And then to use it:
public class MainClass
{
MyClass myclass = new MyClass();
myclass.Value = "Hello World !";
myclass.MyMethod();
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass();
myclass2.Value = "Hello World Again !";
myclass2.MyMethod();
}
Or to be more succinct:
public class MainClass
{
MyClass myclass = new MyClass {
Value = "Hello World !"
};
myclass.MyMethod();
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass {
Value = "Hello World Again !"
};
myclass2.MyMethod();
}
UPDATE
If you absolutely need the classes split (although I wouldn't recommend it), then you need to pass your value into the method class to use it. There are a couple of approaches. Either you have to pass the value down into you methods class (not a very elegant approach):
public class MyClass
{
public string Value { get; set;}
public Methods methods {get; set;)
public MyClass(string value)
{
methods = new Methods(value);
Value = value;
}
public class Methods
{
public string Value { get; set;}
public Methods(string value)
{
Value=value;
}
public void MyMethod()
{
Window.Title = Value;
}
}
}
Or make MyMethod() a static method and pass in the value to use:
public class MyClass
{
public string Value { get; set;}
public MyClass(string value)
{
methods = new Methods(value);
Value = value;
}
}
public static class Methods
{
public static void MyMethod(string Value)
{
Window.Title = Value;
}
}
public class MainClass
{
MyClass myclass = new MyClass {
Value = "Hello World !"
};
Methods.MyMethod(myclass.Value);
System.Threading.Thread.Sleep(Timespan.FromSeconds(10));
MyClass myclass2 = new MyClass {
Value = "Hello World Again !"
};
Methods.MyMethod(myclass2.Value);
}
Both ways are not best practice though as, when you start building more complex classes, having the properties and methods in different places will cause a load of headaches.
As far as I read, creating nested properties don't seem to be possible in c#.
What I want to do is:
Callout callout = new Callout();
callout.Font.Size = 200;
This is the code I currently have
class Callout
{
// nested properties
}
I know how to create properties, but how do I create a nested property?
class Callout {
public Font Font {get;} = new Font();
}
class Font {
public int Size {get;set;}
}
public class Callout {
public Font Font {get;}
}
public struct Font {
public Font(int size) {
Size = size;
}
public int Size {get;}
}
If you really don't want to implement a separate class or struct, here's a tricky way to do what you are asking.
Note: Tricky != Recommended
class Callout : Callout.IFont
{
public interface IFont
{
int Size { get; set; }
}
protected int _fontSize = 0;
int IFont.Size
{
get
{
return _fontSize;
}
set
{
_fontSize = value;
}
}
public IFont Font => this;
}
var callout = new Callout();
callout.Font.Size = 100;
I can't figure out why MessageBox show "false" if nuovo.matrice refers to the same object but not maintain the array reassignment done by the method. Why nuovo.matrice == mat is false if they refers to the same object?
namespace WindowsFormsApplication15
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
class Class1
{
public ClassType[] matrice;
public class ClassType
{
public string a { get; set; }
public int b { get; set; }
}
}
Class1.ClassType[] mat;
private void Form1_Load(object sender, EventArgs e)
{
Class1 test = new Class1();
Class1.ClassType prova = new Class1.ClassType();
test.matrice = new Class1.ClassType[1];
test.matrice[0] = prova;
mat = test.matrice;
mat[0].a = "rtuier";
mat[0].b = 94;
Modify nuovo = new Modify(mat);
nuovo.inizia();
MessageBox.Show((nuovo.matrice == mat).ToString());
}
class Modify
{
public Class1.ClassType[] matrice;
public Modify(Class1.ClassType[] mat)
{
matrice = mat;
}
public void inizia()
{
matrice[0].a = "asuidh";
matrice[0].b = 123;
Class1.ClassType[] newMatrice = new Class1.ClassType[2];
Class1.ClassType ins = new Class1.ClassType { a = "pollo", b = 456 };
newMatrice[0] = matrice[0];
newMatrice[1] = ins;
matrice = newMatrice;
}
}
}
}
The problem is, they don't ref the same object.. because you cannot alter the mat variable in the class. You get a copy of a reference and you're altering the copy. If you want to be able to modify a reference, you should wrap it in a class. Then you'll get a copy of the wrapper reference, but the Class1 field is unique.
Class wrap example:
public class ClassType
{
public string a { get; set; }
public int b { get; set; }
}
public class Class1
{
public ClassType[] classType;
}
public class Wrapper
{
public Class1 WrappedClass1;
}
public class Class2
{
public Wrapper Wrapped;
public Class2(Wrapper wrapper)
{
Wrapped = wrapper;
}
public void ChangeClass1()
{
WrappedClass1.WrappedClass1 = new Class1();
}
}
Class1 class1 = new Class1();
Wrapper wrapper = new Wrapper();
wrapper.WrappedClass1 = class1;
Class2 class2 = new Class2(wrapper);
class2.ChangeClass1();
MessageBox.Show(wrapper.WrappedClass1 == class2.Wrapped.WrappedClass1); // <--- true
I have a class with properties:
public class TaskConfiguration
{
public string Task_Name
{
get; set;
}
public string task_id
{
get; set;
}
}
And somewhere in the code I have a method to set the properties of the class early on upon program execution:
public class TaskManagingProcess
{
public void InsertTaskProperties()
{
TaskConfiguration tc = new TaskConfiguration();
tc.Task_Name = "Sample Task";
tc.task_id = "1";
}
}
Later in execution, in another class, I want to modify the properties of the TaskConfiguration class, but I'm not sure how. If I use the following, it will not work because it creates a new instance of the TaskConfiguration class.
TaskManagingProcess tmp = new TaskManagingProcess;
tmp.InsertTaskProperties();
So how can I do this?
You want to pass the object:
public void InsertTaskProperties(TaskConfiguration config) {
config.Task_Name = "Sample Task";
config.task_id = "1";
}
Then:
TaskManagingProcess tmp = new TaskManagingProcess();
TaskConfiguration config = new TaskConfiguration();
tmp.InsertTaskProperties(config);
(I am making an awfully large assumption about your code.. but this should give you the basic idea)
It looks to me like TaskManagingProcess is a proxy class that's why I would recommend something like:
public class TaskConfiguration
{
public string Task_Name
{
get;
set;
}
public string task_id
{
get;
set;
}
}
public class TaskManagingProcess
{
private TaskConfiguration taskConfiguration;
public TaskManagingProcess(TaskConfiguration taskConfiguration)
{
this.taskConfiguration = taskConfiguration;
}
public void InsertTaskProperties(string taskId, string name)
{
taskConfiguration.task_id = taskId;
taskConfiguration.Task_Name = name;
}
}
So at the end you could do this (see below) and easily add code to handle the access at your TaskConfiguration object:
TaskConfiguration taskConfiguration = new TaskConfiguration() { task_id = "1", Task_Name = "Sample Task" };
TaskManagingProcess taskManaginProcess = new TaskManagingProcess(taskConfiguration);
taskManaginProcess.InsertTaskProperties("2", "Sample Task 2");