I have a public class that is is used to create a dll. It has a variable and a property. Let`s assume it looks like this:
public class Main
{
private int _someInt = 0;
public int SomeInt
{
get { return this._someInt; }
set
{
this._someInt = value;
if (this._someInt == 1)
{
_someInt = 0;
}
}
}
public int ExecuteMain()
{
OtherClass.DoSomething(this.SomeInt);
}
}
I also have another class, in a separate project in the OtherClass class, that has the static DoSomething method:
public static void DoSomething(int someInt)
{
someInt = 1;
}
My problem is that SomeInt property in the Main class is getting set to 1 by the DoSomething method of OtherClass, but this does not trigger the setter in the Main class' property. Am I doing something wrong?
What you are doing is passing SomeInt by value to the DoSomething method, which gets a copy of the int and just changes its local value.
You can:
Pass by ref: public static void DoSomething(ref int someInt)
Pass the Main class and change the value inside DoSomething:
public static void DoSomething(Mainclass main)
{main.SomeInt = 1}
There is no way of doing this,even if you pass the field by reference using ref keyword it's not gonna work because your property has a setter method not your field.You should be changing the value of your property, in order to execute the setter method and perform the validation.
You can do that,passing the current instance of your class instead of the field, for example:
public int ExecuteMain()
{
OtherClass.DoSomething(this); // just pass current instance using 'this'
}
public static void DoSomething(Main obj)
{
obj.SomeInt = 1;
}
If you want to have it invoke the setter logic, one option is to do something like this:
public static void DoSomething(Action<int> setSomeInt)
{
setSomeInt(1);
}
then call it like this:
public int ExecuteMain()
{
OtherClass.DoSomething(x => this.SomeInt = x);
}
The concept here is that what you're really giving the method is not a variable that can be set, but rather an action that can be performed. This is an important distinction, as setting a property is really a kind of action, which can have an arbitrarily complex implementation. This approach is a bit awkward in practice, though, so you'll want to think carefully about what you're really trying to do here and whether there's a better way to express the desired dependency.
Related
How to access and set StaticProperty
public static class StaticClass
{
private bool? _staticValue = null;
public bool StaticProperty => _staticValue ?? ((bool)(_staticValue = GetStaticPropertyValue()));
public static bool GetStaticPropertyValue()
{
//get value
}
}
inside Test Method,
[TestMethod]
public void UnitTestSomeMethod()
{
var consumeClass = new ConsumeClass();
consumeClass.SomeMethod();
}
so that isEnabled variable is set to true in ConsumeClass.SomeMethod
public class ConsumeClass
{
public void SomeMethod()
{
var isEnabled = StaticClass.StaticProperty;
if(isEnabled)
{
//do something
}
}
}
The way your code currently looks like there´s only a dirty way using reflection, because there´s no setter for your property:
var property = typeof(StaticClass).GetProperty("StaticProperty", BindingFlags.Static)?.GetBackingField().SetValue(null, true);
This sometimes is neccessary for large legacy-systems that you can´t easily change but you have the need for unit-tests. However you should change the system as soon as possible, e.g. by using an internal setter:
public static bool StaticProperty { get; internal set; }
and add the InternalsVisibleTo-attribute to your assemby, in order to access its internal members within your test-assembly.
As per your edit the reflection-based approach is a bit easier, as you have a named backing-field which you can assign a new value:
typeof(StaticClass).GetField("_staticValue", BindingFlags.Static).SetValue(null, true);
However be aware that variable-names may change, so the above may fail at runtime when someone renames the backing-field.
say I have the following class
public class MyClass1 {
protected static int MyIntName1 = 0;
public static int GetMyIntName1() {
return MyIntName1;
}
public void MyMethod1() {
MyIntName1 += 1;
}
}
I then have a second class which has a private static int member for which I want to assign as initial value the value of MyIntName1 of the first class. Is there a way to do that ? Does the fact of being private or public make any difference actually ? I tried to do the following
public class MyClass2 {
private static int MyIntName2 = MyClass1.GetMyIntName1(); /* Here the value of MyIntName2
is assigned 0 not matter which value MyIntName1 could have */
public void MyMethod2() {
MyIntName2 = MyClass1.GetMyIntName1(); /*If I do this then MyIntName2 gets
the value of MyIntName1 but that holds only in this method and I would have to
repeat this in any other method of this class that requires the value of MyIntName1...*/
}
}
but no value is assigned to MyIntName2. However, if I do the same inside of a method of the second class, the value of MyIntName1 is assigned but that would only hold in that particular method. To be honest, I am not even sure that what I am trying to achieve makes any sense since I already have a static method which I am trying to assign at declaration to another static member inside a different class. It may be that there is no real purpose in doing this as I could just use the getter method from MyClass1 wherever I need it... However, I am wondering which are all the possibilities of assigning an initial value to class member. Forgive me if the question has already been asked of this does not make any sense.
Thank you.
Following OOP's best practices, is it better to have this code:
class Car {
private Driv driver;
public Driv Driver {
get { return driver; }
set { driver = value; }
}
}
Or this one?
class Car
{
public Driv Driver { get; set; }
}
While the second version is shorter, I feel like I'm breaking the main premise of the Encapsulation concept:
EVERY class should keep its privates to itself.
Hope the answer is not too trivial.
There really is no difference. If no private variable is created by the user then the code will be generated automatically for the private field. However, if the user wishes to do additional logic in the getter or setter of the property then declaring a private field is necessary.
Your first example is what's called a Property with a backing field
The second is called an Automatic property.
The purpose of a property with a backing field is so that you can control access to your private properties.
So... If for instance you want to, make a calculation before returning the value of your private field, you could do it in the one with the backing field.
Or lets say you have a car object with 10,000 miles on the clock... you would probably want to only increment its value using the Drive method, and hide the setter of the Property with the backing field
void Main()
{
var car = new Car();
car.Drive();
Console.WriteLine (car.Miles);
}
public class Car
{
private int miles;
public Car()
{
miles = 10000;
}
public int Miles
{
get
{
return this.miles;
}
}
public void Drive()
{
this.miles += 100;
}
}
You are not breaking encapsulation with the second approach. The second approach is syntactic sugar to make property definition less verbose. The benefit of this approach is that in the future if you need to modify the getter or the setter, you are setup to do so and will not break the API contract.
C#'s properties are simply syntactic representations of some underlying methods and variables. Essentially, the compiler turns:
public int Height { get; set; }
into:
private int height;
public int getHeight() {return height;}
public int setHeight(int h) {height = h;}
So, no you are not defying OOP encapsulation, but instead syntactically simplifying it. You could also do something like public int Height {get;} which is a nice way to create an immutable class member. It simply creates the property without a set method, so only the class itself can alter it.
Now, you only need to use properties with backing fields if you wish to do additional tasks when getting or setting a variable, such as raise an event, or update another variable. The compiler would turn:
private int height;
public int Height { get {return height;} set {height = value; OnHeightChanged();} }
into:
private int height;
public int getHeight() {return height;}
public int setHeight(int value) {height = value; OnHeightChanged();}
Hope this helps!
As a very simplified and stupid example of what I'm dealing with, suppose I had the following class with a simple static int property:
public class MyClass
{
public static int MyVar { get; set; }
}
So, if I wanted to set that property via code, it would be easy enough with something such as:
MyClass.MyVar = 2;
But, how could I take care of (again, to simplify the example) passing in a string and have it converted to an int?
The only way I could think of doing it is to create a helper method such as:
public class MyClass
{
public static int MyVar { get; private set; }
public static void SetMyVar(string sMyVar)
{
MyVar = int.Parse(sMyVar);
}
}
And then in code run:
MyClass.SetMyVar("2");
I would love to know if there was a better way to accomplish this than having to add in that extra method.
Although you definitely shouldn't do this because it's confusing to read, you could create the property this way
class MyClass
{
private static int _property = 0;
public static object Property
{
get
{
return _property;
}
set
{
_property = Convert.ToInt32(value);
}
}
}
You would have to cast this to an int whenever you wanted to use it as an integer but this is best I could think of.
is this what you were trying to do?
class newclass
{
private static int MyVarValue = 0;
public static int MyVar
{
get;
set
{
MyVarValue = Convert.ToInt32(value);
}
}
}
This would not compile because the value that a property gets set to has to be of the same type as the property itself. But if you are taking a list of objects in a constructor and assigning them to the properties, there you can do something like this...
class newclass
{
private static int MyVarValue = 0;
public newclass(List<object> startingList)
{
MyVarValue = Convert.ToInt32(startingList[0]);
}
}
You can use the compiler's method overload resolution to pick a SetMyValue method depending on the type of the argument. Inside each SetMyValue method you have a mechanism to convert all of the different input values to the same underlying type.
Doing this is probably a bad idea - but here goes anyway. It doesn't have quite the semantics that you're asking for but it's close:
//A class with multiple 'set' methods that will silently handle
//type conversions
class MyClass{
private int myValue;
public int MyValue { { get return this.myValue; } }
public void SetMyValue(int value){
this.myValue = value;
}
public void SetMyValue(string value){
this.myValue = Convert.ToInt32(value);
}
}
In statically typed languages, switching types silently in a way that loses information is not a very wise idea. There are other, dynamically typed languages that let you play fast and loose with types but C# is not one of them. You have to go out of your way in C# to get dynamic typing.
Doing this is probably a pain in the butt from a maintenance standpoint. I would put some more thought into the underlying problem that you're trying to solve that lead to this question.
Is it possible to create a class that has a method definition where the method can be accessed statically, and also be accessed via an instance of the class, without having to have two separate names for the method or a separate set of arguments to distinguish the methods as two different methods.
i.e.
public class MyClass
{
public static int GetMyInt()
{
return 1;
}
}
...
MyClass classInst = new MyClass();
int i = MyClass.GetMyInt();
int x = classInst.GetMyInt();
Is this possible in C#? If so, how so?
No. A method is static or is not.
I don't a valid use case you want to allow calling a static method against an instance of a class.
I dont think you can have the cake and eat the cake too.
Static (methods which are called through class) and non-static (methods which are called through instance of class ) are two opposite sides of a coin.
So either it is static or non-static but not both
A static (or class) method is by definition different from an instance method.
An instance method is only accessible when you create an instance of that class;
A static method is always accessible, since it doesn't require class instanciation (provided it is public), at least always accessible within the class itself. You should know, however, that if you have a static variable, any changes made to that variable will affect the class, and have an impact everywhere that variable is used on the application.
eg.
...
static int lastId;
public static int getLastId(){
return lastId++;
}
This is a way you may control an autonumber on a class, since whenever you call getLastId, lastId will be incremented and that is valid for all the application.
edit
the sample code illustrates what happens with a static variable. That said, you should know that overloading is supported on c#. What you cannot have is a pair of methods with the same name tag and the same set and type of parameters.
for eg., this builds ok.
public static int getValue()
{
return 1;
}
public int getValue(int x)
{
return x * 1;
}
but this will throw an error:
public static int getValue(int z)
{
return 1;
}
public int getValue(int x)
{
return x * 1;
}
that is true independently of wether there is a static method or not. This will also generate a compile time error:
public int getValue(int z)
{
return 1;
}
public int getValue(int x)
{
return x * 1;
}
even this will give you an error:
public string getValue(int z)
{
return 1;
}
public int getValue(int x)
{
return x * 1;
}
so, yes, you may have a static method with the same name tag of an instance method, but you may not have the same set and type of parameters.
If you want both static an instance methods to have the same behaviour, then why do you need the intance method really? The static method will do the trick (considering you know the consequences of having a static method and its implications).
Nope. But you can wrap it. But will have to give it a new signature.
public int getMyInt()
{
return GetMyInt();
}