Is it somehow possible for properties to reference each other during the creation of a dynamic object an anonymously-typed object (i.e. inside the object initializer)? My simplified example below needs to reuse the Age property without making a second heavy call to GetAgeFromSomewhere(). Of course it doesn't work. Any suggestion on how to accomplish this?
var profile = new {
Age = GetAgeFromSomewhere(id),
IsLegal = (Age>18)
};
Is something like this possible or not possible with dynamic objects anonymously-typed object initializers?
Unfortunately it's not possible, even with explicitly typed objects. This is because of the way object initializers work. For example:
public class MyClass
{
public int Age = 10;
public bool IsLegal = Age > 18;
}
Yields this compiler error at "IsLegal":
Error 1 A field initializer cannot reference the non-static field,
method, or property 'MyClass.Age' ...
Field initializer can't reference other non-static fields, and since anonymous types don't create static fields, you can't use the value of one field to initialize another. The only way around this, is to declare the variables outside the anonymous type and use them inside the initializer.
int age = GetAgeFromSomewhere(id);
var profile = new {
Age = age,
IsLegal = age > 18
};
Don't complicate thing, keep it simple
//Create a variable
var age = GetAgeFromSomewhere(id);
var profile = new {
Age = age,
IsLegal = age>18
}
What you want is not possible within object intializers. You cannot read properties of the object being initialized. (It does not matter, whether the type is anonymous or not.)
Instead, Create a class
public class Profile
{
public Profile(int id)
{
Age = GetAgeFromSomewhere(id);
}
public int Age { get; private set; }
public int IsLegal { get { return Age > 18; } }
}
Or getting the age the lazy way:
public class Profile
{
private readonly int _id;
public Profile(int id)
{
_id = id;
}
private int? _age;
public int Age {
get {
if (_age == null) {
_age = GetAgeFromSomewhere(_id);
}
return _age.Value;
}
}
public int IsLegal { get { return Age > 18; } }
}
or using the Lazy<T> class (starting with Framework 4.0):
public class Profile
{
public Profile(int id)
{
// C# captures the `id` in a closure.
_lazyAge = new Lazy<int>(
() => GetAgeFromSomewhere(id)
);
}
private Lazy<int> _lazyAge;
public int Age { get { return _lazyAge.Value; } }
public int IsLegal { get { return Age > 18; } }
}
Call it like this
var profile = new Profile(id);
If you don't want to have unnecessary variable, I suggest you use the current object instead :
var profile = new
{
Age = GetAgeFromSomewhere(id),
};
profile.IsLegal = profile.Age > 18;
Related
public class Person
{
private string _myName;
public Person(string myName)
{
_myName= myName;
}
public string Name => _myName;
}
My understanding of object construction use is like this: var obj = new Person("Tim");
An init-only setter assigns a value to the property or the indexer element only during object construction. Following is sample code using init:
public class Person
{
private string _myName;
public string Name
{
get => _myName;
init => _myName= value;
}
}
What is the way to construct an object for such a class so that the init is invoked during object construction? For example, it is:
var obj = new Person("Tim");
var obj = new Person().Name("Tim");
var obj = new Person(); obj.Name="Tim";
I cannot find how object is created in init examples from this msdn link: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/init
The problem is that your class Person doesn't expose a parameterless constructor, the only constructor your class has is one that takes a string as a parameter, meaning you cannot call new Person(); you must supply a parameter of type string. Meaning, the only way to create a new Person in you current example is:
var person = new Person("Anders Hejlsberg");
And after that you cannot modify Name as the initialisation of the object is complete. If you want to change the Name property later, you'll have to remove the init keyword and use a normal setter. If you want to initialize your object like
var person = new Person
{
Name = "Denis Ritchie"
};
(Side note: This is because new Person { ... } implicitly calls a parameterless constructor, i.e it's equal to new Person() { ... }, you could also do new Person("Richard Stallman") { ... } if you wanted to enforce that a Person must always have a Name)
You'll have to give your class a parameterless constructor (or remove your one and only constructor), I'd also recommend using an auto property (i.e no explicit backing field). Re-writing your class like so would result in this:
public class Person
{
public string Name { get; init; }
}
// usage
var person = new Person
{
Name = "Erich Gamma"
};
If you want to enforce that object of type Person always have a Name set, but still want to use init properties for other properties, you can do that like so:
public class Person
{
public string Name { get; init; }
public string Nickname { get; init; }
public Person(string name)
{
Name = name;
}
}
// usage
var linus1 = new Person("Linus Torvalds");
var linus2 = new Person("Linus Sebastian")
{
Nickname = "Linus 'TechTips' Sebastian"
};
It would simply be
var myPerson = new Person() { Name = "Tim" };
or, you can even omit the parenthesis, this would be valid.
var myPerson = new Person { Name = "Tim" };
Also, you can greatly simplify your example, you don't need to define the attribute myName. You can simply use the auto-properties like that:
public class Person
{
public string Name { get; init; }
}
I have code as follow:
struct Name
{
private int age;
public int Age
{
get
{
return age;
}
set
{
age = Age;
}
}
public Name(int a)
{
age = a;
}
};
class Program
{
static void Main(string[] args)
{
Name myName = new Name(27);
Console.WriteLine(myName.Age);
myName.Age = 30;
Console.WriteLine(myName.Age);
}
}
As you can see I am trying to change value of Age using my property. But i am getting still the same value which I pass when I am creating a object of struct Name. I know that struct are immutable in C#, but i thought i would bee able to change field in them. I am very confused. Could someone explain me what is going on?
Structs in C# are not immutable by default. To mark a struct immutable, you should use the readonly modifier on the struct. The reason your properties aren't updating is that your syntax is wrong. You should use the value keyword to dereference the value provided to the setter.
public int Age
{
get
{
return age;
}
set
{
age = value; // <-- here
}
}
i am working with a .net application where i have a web service that returns values in array form and now this array values i want to pass to a class and also as a reference to a private object. But since i am fresh new in programming i do not know how where an with what logic to start.
This is the private obj i created and i want to pass those references where CT is the array type and clsIn is the info that comes from another class but i have no idea how to pass neither of them.
private object TotInfo(clsIn In, CT ct)
{
TotInfo objFromCD = new TotInfo();
return objFromCD;
}
And here is the new class i have created that where i want to pass all the values from clsIn and CT:
public class TotInfo
{
// Object properties
private string LAST_OFFER;
private string LAST_OFFER_DATE;
private string CLOSING_REASON;
private string _NO;
private string _STATUS;
#region "GET/SET Property"
public string NO
{
get { return _NO; }
set { _NO = value; }
}
public string LAST_OFFER
{
get { return _LAST_OFFER; }
set { _LAST_OFFER = value; }
}
public string LAST_OFFER_DATE
{
get { return _LAST_OFFER_DATE; }
set { _LAST_OFFER_DATE = value; }
}
public string CLOSING_REASON
{
get { return _CLOSING_REASON; }
set { _CLOSING_REASON = value; }
}
public string STATUS
{
get { return _STATUS; }
set { _STATUS = value; }
}
#endregion
#region "Costruttori"
public CardsTotInfo() { }
public CardsTotInfo(string No, string lastOffer, string lastOfferDate, string closingReason, string status)
{
this.NO = No;
this.LAST_OFFER = lastOffer.ToUpper();
this.LAST_OFFER_DATE = lastOfferDate.ToUpper();
this.CLOSING_REASON = closingReason.ToUpper();
this.STATUS = status.ToUpper();
}
}
I have passed, or better say i think i have passed in the correct way the values of clsIn but i do not know how to pass the properties of the array type CT[].
I really need help.
Thank you in advance.
If CT is an object array and the data you get from the web service always comes in the same order, for instance using an arbitrary example:
object[] CT = { 1, DateTime.Now, "foo", true }
If you know that each property data inside the array will always be at the same index (you will always have a int in index 0 representing an Id, and a DateTime on index 1 representing the last offer day and so on)
I would say you need to set each property "manually":
private object TotInfo(clsIn In, CT ct)
{
TotInfo objFromCD = new TotInfo();
//get data from DB
//set the data from the array into the class properties
objFromCD.Id = (int)ct[0];
objFromCD.LastOfferDate = (DateTime)ct[1];
objFromCD.ClosingReason = (string)ct[2];
objFromCD.Available = (bool)ct[3];
return objFromCD;
}
I may not have a good grasp of the ?? operator yet and ran into a design flaw I couldn't explain.
Compare the following two properties, the only difference being how there are initialized: the first explicitly initialized, while the second with the ?? operator (or am I doing it wrong here?).
If I run data init with both properties, the collection based on the first property comes up populated as expected, while the second one with the ?? operator never gets populated and comes up with 0 elements in the collection.
Surely something is wrong here in my assumption; what is the flaw here?
P.S. Please ignore the Set method which is to implement INotifyPropertyChanged in the base class and has no bearing on this issue (which is confined to the type of initialization).
// property version 1
private ObservableCollection<UserName> _userNameColl = new ObservableCollection<UserName>();
public ObservableCollection<UserName> UserNameColl
{
get { return _userNameColl; }
set { Set(ref _userNameColl, value); }
}
// property version 2
private ObservableCollection<UserName> _userNameColl;
public ObservableCollection<UserName> UserNameColl
{
get { return _userNameColl ?? new ObservableCollection<UserName>(); }
set { Set(ref _userNameColl, value); }
}
// a simple class for creating object collection
public class UserName
{
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
}
// a simple test populating the collection
for (int i = 0; i < 4; i++)
{
// silly data init just for test
UserNameColl.Add(new UserName()
{
Name = $"UserName No {i}",
Age = 20 + i,
Email = $"email{i}#local.lan"
});
}
The second one never initializes your field but always returns a new collection. Try this one instead:
public ObservableCollection<UserName> UserNameColl
{
get { return _userNameColl ?? (_userNameColl = new ObservableCollection<UserName>()); }
set { Set(ref _userNameColl, value); }
}
I have a class baseClass, and a list of objects of the baseClass. What i want to achieve is that i have to dynamically assign the instance number to each object in the list. for that what am doing is that use a constructor to do this.
Following is the class definition:
public class baseClass
{
private int _InstanceNumber;
private int _MyIntVal;
private string _MyString;
public string MyString
{
get { return _MyString; }
set { _MyString = value; }
}
public int MyIntVal
{
get { return _MyIntVal; }
set { _MyIntVal = value; }
}
public int MyProperty
{
get { return _InstanceNumber; }
}
public baseClass(int instance)
{
_InstanceNumber = instance;
}
}
The creation of the List of objects is as follows:
int instanceNumber = 0;
List<baseClass> classList = new List<baseClass>();
classList.Add(new baseClass(instanceNumber++) { MyString = "sample1", MyIntVal = 10 });
classList.Add(new baseClass(instanceNumber++) { MyString = "sample2", MyIntVal = 11 });
I know it is not the actual way for creating this. it does not give the index number actually. how can i calculate the instance number?
Consider the following scenario, that am creating another list of objects then it hard to maintain the instance number. or if i create another object(this also be an instance) external to the list.
int instanceNumber = 0;
List<baseClass> anotherClassList = new List<baseClass>();
classList.Add(new baseClass(instanceNumber++) { MyString = "sample1", MyIntVal = 10 });
classList.Add(new baseClass(instanceNumber++) { MyString = "sample2", MyIntVal = 11 });
Updates:
This is my temporary solution for this. i need proper way/ method to maintain instance number
If you want to find the index of item in the list, you should ask it from the list, not the item like:
var index = list.IndexOf(item);
But it seems that you expect the item to be aware of its position in the list. In order to do this, you should pass the list to the item so it can use it to find its own place in it:
public class Item
{
private List<Item> _containerList;
public Item(List<Item> containerList)
{
_containerList = containerList;
}
public int InstanceNumber
{
get { return _containerList.IndexOf(this); }
}
}
and change your code to:
List<Item> classList = new List<Item>();
classList.Add(new Item(classList ) { ... });
classList.Add(new Item(classList ) { ... });