Is this the proper use of Action<T> - c#

As I understand Func and Action; An Action does not return a value, and a Func does. In the below example I have a child class create an instance of "SomeContent" and pass a reference back to the parent class. My questions are:
Does this.ContentDelagate(content) pass by reference or by value?
In the below example, should I have used Func as I want a reference to an the instantiated SomeContent object? If so can you provide an example?
namespace DelegateTut
{
class Program
{
static void Main(string[] args)
{
TestClass myTest = new TestClass();
myTest.ContentDelagate += ContentDelegateHandler;
myTest.RunDel();
Console.Write("Press Enter to exit...\n");
Console.ReadLine();
}
public static void ContentDelegateHandler(SomeContent content) {
Console.WriteLine(content.ValueOne);
Console.WriteLine(content.ValueTwo);
}
}
}
public class TestClass {
public TestClass() { }
public Action<SomeContent> ContentDelagate { get; set; }
public void RunDel() {
SendContentToMainThread();
}
public void SendContentToMainThread() {
SomeContent content = new SomeContent {
ValueOne = "Hello",
ValueTwo = "World"
};
this.ContentDelagate(content);
}
}
public class SomeContent {
public String ValueOne { get; set; }
public String ValueTwo { get; set; }
public SomeContent() { }
}

Does this.ContentDelagate(content) pass by reference or by value?
This question is a little confusing. We are dealing with both a getter and a delegate as well. I think its clearer to show:
public void SendContentToMainThread()
{
SomeContent content = new SomeContent
{
ValueOne = "Hello",
ValueTwo = "World"
};
Action<SomeContent> myDel = ContentDelagate;//Property Get
myDel(content);//invoke delegate
Console.WriteLine(content.ValueOne);//refer to this below
}
The handler is called as part of the multicast delegate. The handler is being passed a class which is a reference type. In C# reference and value types are passed by value. The underlying value that is copied could be a value (value type) or a location in memory (reference type).
Because this is a reference type it has reference type behavior:
public static void ContentDelegateHandler(SomeContent content)
{
Console.WriteLine(content.ValueOne);
Console.WriteLine(content.ValueTwo);
content.ValueOne = "updated";
}
Now the modified code above Console.WriteLine(content.ValueOne); will print out the word "updated".
In the below example, should I have used Func as I want a reference to
an the instantiated SomeContent object? If so can you provide an
example?
There's nothing being returned in this case so no you should not use Func. Func does not have any impact whatsoever on your desire to have reference type behavior.

Related

C# Dynamic object cannot access variable as assigned in base constructor

I have a dynamic object Type that I assign via a constructor. Here is a simplified version of my code:
public static void Main(string[] args)
{
var x = new Shirt("Collared");
}
class Shirt {
public dynamic Type = new { };
public string ProblemVariable;
public Shirt() { }
public Shirt(string type) {
ProblemVariable = "Assigned in Constructor";
if (type == "Collared") {
Type = new Type.Collared();
}
}
class Type : Shirt {
public Type() { }
public Type(string value)
{
}
}
class Collared : Type { }
In Main(), calling x.Type.GetType() returns that my dynamic x.Type is a Type.Collared. In Type.Collared, I would like to create a function that accesses string ProblemVariable from base class Shirt:
class Collared : Type {
public void GetProblemVariable() {
Console.WriteLine(ProblemVariable);
}
}
Doing so returns a NullReferenceException. If I assign ProblemVariable as "Not modified" in my class definition:
class Shirt {
public string ProblemVariable = "Not modified";
My function GetProblemVariable returns ProblemVariable as "Not Modified".
While I am obviously able to access ProblemVariable from base class Shirt, why does Type.Collared not return ProblemVariable as "Assigned in Constructor" as defined in constructor Shirt(string type)?
Because Type = new Type.Collared(); calls base constructor public Shirt() { }, not public Shirt(string type), so ProblemVariable is not assigned.

c# initialize static variable from different classes

What I have is:
public static class IDs {
public static string someID { get; set; }
static IDs() {
log.info(someID);
// use someID here
}
}
public class otherClass {
public void otherMethod(string sym) {
IDs.someID = sym;
}
}
and then using an instance of otherClass like this:
otherClassInstance.otherMethod("someStringSymbol");
I dont have any build errors, but log.info(someID); is printing null.
I was expecting it to be someStringSymbol.
This is because the static constructor is called automatically before the first instance is created or any static members are referenced..
This means that when an instance of otherClass invokes IDs.someID = sym; the first operation that gets executed is the static constructor, i.e. the code inside static IDs().
At this point the static variable has not yet been initialized, and you are basically executing log.info(null);.
After the static constructor completes, the variable is initialized, so you should be able to see its value inside otherMethod, after the first reference of IDs.
Given the OP's requirement:
I want to use the value passed in someID in a switch statement
The solution could be to simply execute a static method whenever a new value is set, with the help of explicit getters and setters:
public static class IDs
{
private static string _someID; // backing field
public static string SomeID
{
get { return _someID; }
set
{
_someID = value;
DoSomethingWithSomeID();
}
}
private static DoSomethingWithSomeID()
{
// Use SomeID here.
switch (IDs.SomeID)
{
...
}
}
}
public class OtherClass
{
public void OtherMethod(string sym)
{
// This will set a new value to the property
// and invoke DoSomethingWithSomeID.
IDs.SomeID = sym;
}
}
DoSomethingWithSomeID will be invoked every time someone sets a new value to SomeID.
I dont think what you are trying to do is suited to static classes. I would try the following
public class IDs{
public string someID{ get; set; }
public IDs(string someId){
this.someID = someId;
log.info(this.someID);
//use someID here
}
}
pulic class otherClass{
public otherMethod(string sym){
IDs id = new IDs(sym);
}
}
public class anotherClass{
//access instance of otherClass in wrp and call otherMethod()
wrp.otherMethod("someStringSymbol")
}

Pass by Value in C#

How can I pass an object of a "MyClass" (C#) by Parameter-by-Value to a method? example:
MyClass obj = new MyClass();
MyClass.DontModify(obj); //Only use it!
Console.Writeline(obj.SomeIntProperty);
...
public static void DontModify(MyClass a)
{
a.SomeIntProperty+= 100;// Do something more meaningful here
return;
}
By default object types are passed by value in C#. But when you pass a object reference to a method, modifications in the object are persisted. If you want your object to be inmutable, you need to clone it.
In oder to do it, implement the ICloneable interface in your class. Here is a mock example of how to use ICloneable:
public class MyClass : ICloneable
{
private int myValue;
public MyClass(int val)
{
myValue = val;
}
public void object Clone()
{
return new MyClass(myValue);
}
}
By default, it is passed by value. However, you're passing the object reference by value, which means you can still edit values within the object.
In order to prevent the object from being able to change at all, you would need to actually clone the object prior to passing it into your method. This would require you to implement some method of creating a new instance that is a copy of your original object, and then passing in the copy.
public static void DontModify(MyClass a)
{
MyClass clone = (MyClass)a.Clone();
clone.SomeIntProperty+= 100;// Do something more meaningful here
return;
}
You could create a Clone method on your object to pass the return value to your method. C# cannot pass reference types by value so this might be a good alternative.
public MyClass CreateClone()
{
return new MyClass() { SomeIntProperty = this.SomeIntProperty };
}
class Program
{
static void Main(string[] args)
{
Person p1 = new Person()
{
Name = "Alsafoo",
Address = new Address()
{
City = "Chicago"
}
};
Person p2 = new Person(p1.Address);
p2 = p1.GetClone(CloningFlags.Shallow);
p2.Name = "Ahmed";
p2.Address = new Address(){City = "Las Vegas"};
Console.WriteLine("p1 first name: {1} --- p1 city: {2} {0}p2 first name: {3} ---- p2 city: {4}",
Environment.NewLine, p1.Name, p1.Address.City, p2.Name, p2.Address.City);
Console.ReadKey();
}
}
public class Person
{
public Person()
{}
public Person(Address a)
{
Address = a;
}
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string City { get; set; }
}
Download this extension
https://www.nuget.org/packages/CloneExtensions/1.2.0
Created a Extention method
using System.Text.Json;
namespace Student.Utilities
{
public static class CloneExtension
{
public static T Clone<T>(this T cloneable) where T : new()
{
var toJson = JsonSerializer.Serialize(cloneable);
return JsonSerializer.Deserialize<T>(toJson);
}
}
}
Now, while calling, call it like this to pass the clone to another method:
public void CreateStudent(Student student)
{
Student clonedStudent = student.Clone<Student>();
_repository.CreateStudent(clonedStudent);
}

Behavior of String in C#

I am a C++ programmer, now working on a C# project.
I am trying to understand in the below snippet why the value of string does not change even though the function is changing its value, I thought it is an object and would be passed as a reference.
public class TestClass
{
public TestClass(String passedStr)
{
passedStr = "Change me";
}
}
class Program
{
static void Main(string[] args)
{
String aString="I am what i am";
TestClass obj = new TestClass(aString);
Console.WriteLine(aString);
}
}
But behavior with user defined classes are different.
public class TestClass
{
private int x;
public int ID
{
get
{
return x;
}
set
{
x = value;
}
}
public TestClass(int a)
{
x = a;
}
}
public class Tester
{
public Tester(TestClass obj)
{
obj.ID = 999;
}
}
class Program
{
static void Main(string[] args)
{
TestClass obj = new TestClass(555);
Tester tester = new Tester(obj);
Console.WriteLine(obj.ID);
}
}
Let's go back to basics.
A variable is a storage location.
A variable of type string is a storage location that stores either null, or a reference to a string.
"passedStr" and "aString" are different variables.
When you call "new TestClass(aString)" you create a new storage location for "passedStr" and copy the contents of "aString" into it. You now have two variables that have the same content: a reference to a string.
Inside the constructor you change the value stored in the storage location for "passedStr". "aString" remains the same.
The "ref" and "out" keywords in C# mean "make the formal parameter and the argument aliases of each other". In that case you have only one variable with two different names. When you change one of them the other one changes as well, because they are the same variable.
No, it's passed by value; there's no ref keyword.
It's passing a reference type (here, a class) by value (no ref keyword), just like passing a copy of a pointer in C++. You're reassigning the pointer, not the actual data (which you can't do with strings anyway).
If you need pass-by-reference, try:
public TestClass(ref String passedStr)
{
passedStr = "Change me";
}
...
TestClass obj = new TestClass(ref aString);
Strings are passed by reference but the pointer is passed by value in C#. If you want to pass the string by reference you'll have to make use of the ref key word.
For example:
public class TestClass
{
public TestClass(ref string passedStr)
{
passedStr = "Change me";
}
}
class Program
{
static void Main(string[] args)
{
string aString="I am what i am";
TestClass obj = new TestClass(ref aString);
Console.WriteLine(aString); // "Change me"
}
}
passedStr is not the string, but a constructor parameter that holds a reference to the string. All your TestClass constructor is doing is changing the string that this parameter references. It has no effect outside the constructor.
What you are doing in the constructor, is that you are assigning a new String literal to the local variable passedStr.
In C, the equivalent function would look something like this:
Testclass constructor_testclass(char* passedStr) {
passedStr = "Change me";
}
I think it's obvious that this function does not change the value of the char* in the calling function.
The object I am what i am is being passed by reference, but the reassignment is to a local variable. You don't change the original object, but instead assign a new object (Change me) to the location of the argument.
public class Employee
{
public string ID { get; set; }
public string Name { get; set; }
public override string ToString()
{
return string.Format("ID = {0} Name = {1}", ID, Name);
}
}
public class TestClass2
{
public TestClass2(Employee e)
{
e.ID="007";
e.Name="james";
}
}
static void Main()
{
Employee e = new Employee();
e.ID = "0";
e.Name = "nobody";
TestClass2 t = new TestClass2(e);
Console.WriteLine(e); //Output ID = 007 Name = James
}
strings are passed by reference but the pointer is passed by value in C#
Parameter passing in C# by Jon Skeet

Illegal declaration of a property and a static function. why?

Can somone explain why I get this error on this code?
Error 1 The type
'ConsoleApplication1.TestClass'
already contains a definition for
'IsThisOK'
class TestClass
{
public bool IsThisOK { get; set; }
public static bool IsThisOK(string str)
{
return true;
}
public static void Test()
{
TestClass c = new TestClass();
c.IsThisOK = IsThisOK("Hello");
}
}
You're trying to define a property and a method with the same name. While you can have multiple methods that override each other (with different argument lists), you cannot have a property and a method that share the same name
You've declared IsThisOK twice, at line 3 and line 5 (property and static function).
Try to imagine how could the compiler could figure out to which you are referring later on?
Because you cannot provide same name to a function and a Property.
You cannot overload function with property.
You can use it in this way:
class TestClass
{
public bool IsThisOK { get; set; }
public static bool isThisOK(string str)
{
return true;
}
public static void Test()
{
TestClass c = new TestClass();
c.IsThisOK = isThisOK("Hello");
}
}
As other pointed out, you cannot have a method and a property with the same name.
However, you can more or less work around this by using an extension method if you like:
static class TestClassExtension
{
public static bool IsThisOK(this TestClass, string str)
{
return true;
}
}
class TestClass
{
public bool IsThisOK { get; set; }
public static void Test()
{
TestClass c = new TestClass();
c.IsThisOK = this.IsThisOK("Hello");
}
}

Categories

Resources