Nested Class with get only property - c#

assuming that i have below class:
public class ClassA
{
public string ElementA { get; }
public string ElementB { get; }
}
public class ClassB
{
public ClassA ElementC = new ClassA()
{
ElementA = "Sample Value A",
ElementB = "Sample Value B"
};
public ClassB ElementD = new ClassA()
{
ElementA = "Sample Value C",
ElementB = "Sample Value D"
};
}
how can i nest ClassA inside and as an element of ClassB with only a { get; } property. I am trying to instantiate a class where it can only be accessed via the { get; } assessor as i want it to behave as a fixed variable/value. the IDE (Visual Studio) throws me an error whenever i try this approach which states:
Property or indexer 'ClassA.ElementA' cannot be assigned to -- it is
read only
writing ClassA as:
public class ClassA
{
public string ElementA { get; set; }
public string ElementB { get; set; }
}
makes ClassB's ClassA Element editable but does not throw an error in the IDE (Visual Studio).
how or is it possible to do something of my idea ? Thanks.

If you don't want the properties modified from outside of the class, add a private setter and modify the class's constructor to set the values upon instantiation:
public class ClassA
{
public ClassA(string elementA, string elementB)
{
ElementA = elementA;
ElementB = elementB;
}
public string ElementA { get; private set; }
public string ElementB { get; private set; }
}
Then instantiate it from ClassB like this:
public class ClassB
{
public ClassA ElementC = new ClassA("Sample Value A", "Sample Value B");
}

A property defined like this:
public Foo Bar { get; }
Is equivalent to this:
private readonly Foo bar;
public Foo Bar { get { return this.bar; } }
The readonly keyword means the field can only be assigned in a class's constructor (or the field initialization list, which is executed before the constructor method's body).
Because the field is private, you cannot set it from outside the type's access scope, and because it's a readonly field it must be in the constructor - so to use an externally-provided value you must use a constructor parameter:
public ClassA(Foo value) {
this.Bar = value;
}

Related

Does primary constructor in C# generates init only or protected set property?

Consider the following code:
public enum TransactionType{Foo,Bar}
public abstract record Transaction
{
public TransactionType Type { get; }
protected Transaction(TransactionType type)
{
Type = type;
}
}
public record InheritedTransactionBarOnly: Transaction
{
public InheritedTransactionBarOnly(): base(TransactionType.Bar){}
}
public static class Program
{
public static void Main()
{
var iWantThis = new InheritedTransactionBarOnly();
//var iDontWantThis = new InheritedTransactionBarOnly{Type = TransactionType.Foo}; // this shouldn't be possible
}
}
Rider is suggesting to convert to a primary constructor:
but I do believe this is wrong, as this will allow for Type to be set during the initialization of the inherited record:
var inheritedTransaction = new InheritedTransactionBarOnly
{
Type = TransactionType.Foo // This code compiles only after Rider suggested change, but not before
}
Is my understanding is wrong or it is just a bug in Rider?
P.S. This is what Transaction looks like after Rider's conversion:
public abstract record Transaction(TransactionType Type)
{
}
I made a few test cases to show the difference between how records are built. The following is just for class records, I'm not sure if the same is true for struct records.
Starting with your example, SomeProperty { get; } this means the property can only be set during construction, not from new { SomeProperty = ... } code. But record primary constructor (the refactor suggestion) declares properties {get; init;} by default, which allows setting in new ... blocks. However, note that you can redefine properties inside the declaration; see the AltRecord record below. Perhaps this is more concise...
See record reference in the section "If the generated auto-implemented property definition isn't what you want" ...
So to answer your question, yes, this seems like a mistake in the refactor, because behavior is not the same. Here is some code to show the differences.
public abstract record GetOnlyExample
{
// Readonly property (cannot set in new { SomeProperty = ... } )
public int SomeProperty { get; }
// Property can only be set once, from protected constructor.
protected GetOnlyExample(int someProperty)
{
SomeProperty = someProperty;
}
}
public record ConcreteGetOnlyExample : GetOnlyExample
{
// Concrete implementation, can only set SomeProperty through base constructor.
public ConcreteGetOnlyExample() : base(1) { }
}
public abstract record GetInitExample
{
// Readonly property, allow in init (can set in new { SomeProperty = ... } )
public int SomeProperty { get; init; }
// Property can only be set during construction, or init.
protected GetInitExample(int someProperty)
{
SomeProperty = someProperty;
}
}
public record ConcreteGetInitExample : GetInitExample
{
// Concrete implementation, can only set SomeProperty during init/construction.
public ConcreteGetInitExample() : base(1) { }
}
// Primary constructor, creates: public int SomeProperty { get; init; }
public abstract record PrimaryConstructor(int SomeProperty)
{
}
public record ConcretePrimaryConstructor : PrimaryConstructor
{
// Concrete implementation, can only set SomeProperty during init/construction.
public ConcretePrimaryConstructor() : base(1) { }
}
// Primary constructor, creates: public int SomeProperty { get; init; }
public abstract record AltRecord(int SomeProperty)
{
// redefine SomeProperty to be readonly (no init)
public int SomeProperty { get; } = SomeProperty;
}
public record ConcreteAltRecord : AltRecord
{
public ConcreteAltRecord() : base(1) { }
}
internal class Program
{
static void Main(string[] args)
{
// compile error: not allowed during init:
// ConcreteGetOnlyExample aaa = new ConcreteGetOnlyExample() { SomeProperty = 5 };
// can set during init:
ConcreteGetInitExample bbb = new ConcreteGetInitExample() { SomeProperty = 5 };
// implicit init created through primary constructor:
ConcretePrimaryConstructor ccc = new ConcretePrimaryConstructor() { SomeProperty = 8 };
// compile error: SomeProperty was redefined as `get` only, can't set during init
//ConcreteAltRecord ddd = new ConcreteAltRecord() { SomeProperty = 9 };
}
}

C# two objects with the same reference

I have base class that save all property value in a Dictionary. but I want to property value and value in Dictionary has save value. if property value change then change dictionary value and if change value in dictionary , change property value. In Constructor I use reflection but after finish constructor I want not used reflection because of performance.
Type of dictionary value is following (in my project its more complex):
public class AgentProperty
{
public object Value;
public string Name;
public AgentProperty(string name, object value)
{
Value = value;
Name = name;
}
}
The Base Class is following:
public class BaseClass
{
private Dictionary<string,AgentProperty> Dictionary = new Dictionary<string, AgentProperty>();
public AgentProperty this[string key]
{
get { return (AgentProperty)Dictionary[key]; }
set { Dictionary[key] = value; }
}
public void Add(AgentProperty ap)
{
Dictionary.Add(ap.Name, ap);
}
public void SetDict(BaseClass o)
{
var objectType = o.GetType();
foreach (var property in objectType.GetProperties())
{
AgentProperty agentProperty = new AgentProperty(property.Name, property.GetValue(o));
Add(agentProperty);
}
}
}
The sample class that inherited from BaseClass. This class can have any type of property.
public class TmpClass : BaseClass
{
public TmpClass(){
SetDict(this);
}
public string X { get; set; }
public int y { get; set; }
public string Z { get; set; }
public TimeSpan T { get; set; }
}
Is there any way to do this?

Get property default value on class initialize

Let's say we have some class CarsBase
public class CarsBase
{
public string DisplayName { get; set; }
}
Then we have some other class Toyota
public class Toyota : CarsBase
{
public EngineType EngineType { get; set; }
}
Then we are initializing our class instance by using object initializer like so:
var myVar = new Toyota()
{
// DisplayName = "", ← We could do this by our hands, but can it be done automatically?
EngineType = EngineType.UZ
}
Question: Is there any way to fill CarsBase's DisplayName property automatically on object initialize?
Like, if I had several more car classes (BMW, Suzuki , etc.), each is extending CarsBase and as a result have DisplayName property in each class.
This sounds like something that should be done in a constructor.
public class Toyota : CarsBase
{
public Toyota() : base()
{
base.DisplayName = "Toyota";
}
public EngineType EngineType { get; set; }
}
Another option, however less recommended, instead of getting/setting a DisplayName in the same sense, the base class could be changed to use reflection retrieve the classname and use that as the display name:
public class CarsBase
{
public string DisplayName
{
get
{
return this.GetType().Name;
}
}
}
This method should just return the "Toyota" from the classname, however would prevent usage of spaces or other special characters. Reflected code such as this also has a tendency to be slower.
Create a constructor to pass dispay name (or other parameters as required)-
Toyota(string displayName)
{
DisplayName = displayName;
EngineType = EngineType.UZ;
}
Then you can call like this-
new Toyota("some display name");
Just set the property value in the constructor. Something like this:
internal class Program
{
private static void Main(string[] args)
{
Toyota t = new Toyota() { EngineType = new EngineType() };
Console.WriteLine(t.DisplayName);
Console.ReadLine();
}
}
public class CarsBase
{
public string DisplayName { get; set; }
}
public class Toyota : CarsBase
{
public EngineType EngineType { get; set; }
public Toyota()
{
// set the default Display Name
// that way you don't have to set it everytime
this.DisplayName = "Oh what a feeling!";
}
}
public class EngineType { }
Yes, it can be done during the initialization stage of object where constructor is fired . I have created two classes
* one for holding enum constant value for engine_Types --> EngineType
one for explaining the inheritance,Constructor-Chaining, creating an instance of class which is an object----> CarsBase
[pre]
namespace stacketst
{
public class CarsBase
{
public string DisplayName { get; set; }
public CarsBase()
{
//called when CarBase object is initialized
DisplayName = "Base Car";
}
}
public class Toyota : CarsBase
{
//getters , setters called as properties in C#
public int number_of_wheels { get; set; }
public double fuel_capacity { get; set; }
public string engine_type { get; set; }
public Toyota() //called when an instance of Toyota is created
{
//assinging value to this property calls set
fuel_capacity = 4.2;
number_of_wheels = 4;
engine_type = EngineType.name_engines.UZ.ToString();
}
}
public class TestClass
{
static void Main()
{
//when below line is executed,constructor is fired & the initialization of variable inside constructor takes place
var myVar = new Toyota();
Console.WriteLine(myVar.DisplayName);
}
}
}
namespace stacketst
{
public class EngineType
{
//enums to hold constants, common for any Car Class
public enum name_engines
{
V12, V10, V8, V6, UZ
};
}
}
[/pre]

c# Access specific class with Enum GetName

RootObject.cs
public class RootObject
{
public Class1 Class1 { get; set; }
public Class2 Class2 { get; set; }
public Class3 Class3 { get; set; }
}
Class1.cs (Class2, Class3, ....)
public class Class1
{
public string name { get; set; }
public string surname { get; set; }
}
Enum.cs
public enum Classes
{
Class1,
Class2,
Class3
}
MyFunction.cs
nItemCount = Enum.GetNames(typeof(Classes)).Length; /* equal to 3 */
for (i=0 ; i < nItemCount; i++)
{
string name = RootObject.(Enum.GetName(typeof(Classes), i)).name;
}
I want to get the name value of Class1, Class2, Class3, etc. like a method above.
I wish I could explain my problem.
I need a solution for accessing all classes in a loop with the enum value.
Can anyone please help ?
You will have to change your code to be like below. Note I have used Classes as datatype for the Property.
public class RootObject
{
public Classes ClassProp { get; set; }
}
public enum Classes
{
Class1,
Class2,
Class3
}
And then you can access the properties by using following code. You will have to instantiate the class and then access the property as they are Object level properoties and not static. Also, note that you will have to set the properties to get the appropriate enum value.
RootObject rootObj = new RootObject();
rootObj.ClassProp = Classes.Class2;
var class2 = rootObj.ClassProp;
If your classes share common members, either move those to a common base class or let the classes implement a common interface (or both).
public abstract class Person
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class Customer : Person
{
public Address DeliveryAddress { get; set; }
}
public class Employee : Person
{
public string Profession { get; set; }
}
Then, instead of creating individual properties for each the classes, add them to an array and use the enum values as index:
public enum PersonType
{
Customer = 0,
Employee = 1,
Supplier = 2
}
public class RootObject
{
Person[] _persons = new Person[] {
new Customer(),
new Employee(),
new Supplier()
};
public Person[] Persons { get { return _persons; } }
}
Now you can access the persons easily with
foreach (PersonType personType in (PersonType[])Enum.GetValues(typeof(PersonType))) {
Person p = rootObject.Persons[(int)personType];
string name = p.Name;
string surname = p.Surname;
// ...
}
First, if all of your types Class1, Class2, Class3, ..., ClassWhatNot share same property definitions, it is better to move these same property definitions into a common BaseClass which the aforementioned classes will inherit from.
class BaseClass
{
public string Name { get; set;}
}
class Class1 : BaseClass
{
...
}
class Class2 : BaseClass
{
...
}
//... do the definition of Class3 in the same way
Implement the RootClass as follows (note that i changed the names a bit to make it clearer how things work):
class RootClass
{
public enum PropertyEnum
{
propClass1,
propClass2,
propClass3
}
public Class1 propClass1 { get; set; }
public Class2 propClass2 { get; set; }
public Class3 propClass3 { get; set; }
public BaseClass GetPropertyByEnum(RootClass.PropertyEnum enumValue)
{
PropertyInfo pi = typeof(RootClass).GetProperty(enumValue.ToString());
return pi.GetValue(instance, null) as BaseClass;
}
}
With the method GetPropertyByEnum you can easily do:
RootClass rootObj = ...create/get the root object
foreach(RootClass.PropertyEnum enumValue in Enum.GetValues(typeof(RootClass.PropertyEnum))
{
BaseClass b = rootObj.GetPropertyByEnum(enumValue);
if (b != null) Console.Out.WriteLine("{0}.name = {1}", enumValue.ToString(), b.Name);
}
Note, that when not using a common base class (such as BaseClass in my example), GetPropertyByName could only return references of type Object. In such a case you would need to know how to cast the returned object to the appropriate type, which would make the whole endeavour of accessing properties by enum mostly pointless...

Update the Base Class attributes when instantiate Child class C#

I want the following, is it possible in C#
public class BaseClass
{
public string Name {get;set;}
public DateTime Login {get;set;}
}
public class ChildA : BaseClass
{
public string SchoolName{get; set;}
public string ClassName{get; set;}
}
public class childB : BaseClass
{
public string StreetAdrees{get; set;}
}
Now I want that if I create an instance of any child class Name="John" and Login "2013-12-12" or from database already set its irritating to set these attribute for every class
just like that
ChildA obj=new ChildA();
obj.Name and obj.Login already have Data
Specify constructor in base class, then create constructors in child classes which inherit from base classes constuctor like below
public class ChildA : BaseClass
{
public ChildA():base(){}
public string SchoolName{get; set;}
public string ClassName{get; set;}
}
public class BaseClass
{
public BaseClass()
{
//set Data
.....
}
....
}
read more about base keyword
In the example below, children would actually point to the same instance of base
The example uses cache, but it could be anything else (session, application state, etc).
public class BaseClass
{
private string _name;
private DateTime _login;
public string Name
{
get
{
return Instance._name;
}
set
{
_name = value;
}
}
public DateTime Login
{
get
{
return Instance._login;
}
set
{
_login = value;
}
}
public static BaseClass Instance
{
get
{
// check if null, return a new instance if null etc...
return HttpContext.Current.Cache["BaseClassInstance"] as BaseClass;
}
set
{
HttpContext.Current.Cache.Insert("BaseClassInstance", value);
}
}
}
public class ChildA : BaseClass
{
public string SchoolName { get; set; }
public string ClassName { get; set; }
}
public class childB : BaseClass
{
public string StreetAdrees { get; set; }
}
testing it:
BaseClass.Instance = new BaseClass() { Login = DateTime.Now, Name = "Test" };
ChildA ch = new ChildA();
ChildA ch2 = new ChildA();
childB chb = new childB();
Response.Write(ch.Login.Millisecond);
Response.Write("<BR/>");
Response.Write(chb.Login.Millisecond);
Result:
906
906

Categories

Resources