is something like the penultimate line here possible? I.E. referring to other properties within the declaration itself?
In my actual code, A and B are set to complex LINQ Enumerables (which is fine) and C could be something like A.Count():
class Thing {
public int A;
public int B;
public int C;
}
Thing myThing = new Thing() {
A = 1,
B = 2,
C = A+B
}
Just trying to find the most efficient way of constructing myThing.
Consider this example:
int A = 0;
int B = 0;
int C = 0;
MyThing myThing = new MyThing() {
A = 1,
B = 2,
C = A + B
}
// myThing.A == 1
// myThing.B == 2
// myThing.C == 0
So, no; it is not possible. Use any of the other answers instead.
Sadly, it's not possible to retrieve a property's value in the object's initializer.
I don't think A and B would be updated before you can reference them to use in C. The solution in my eyes is to simple assign A and B to variables before creating the Object:
var variable1 = 1
var variable2 = 2
Thing myThing = new Thing() {
A = variable1,
B = variable2,
C = variable1+variable2
}
that way you can be sure both variables are changed before you use them for C
Edit: "do I have no choice but to define property C after initialising the object?"
The problem is that A and B aren't initialised yet, so you can't use them to create C. But if you initialise them under another name(variable 1 and variable 2 in the above example) you can then go on to use those values to get C
Object initialiser syntax you're using is just a shortcut for assigning the values, so you could do this:
Thing myThing = new Thing() {
A = 1,
B = 2};
myThing.C =myThing.A + myThing.B;
Properties to the rescue (based on your example)
class Thing {
public IEnumerable<someType> A { get; set; }
public IEnumerable<someType> B { get; set; }
public int C { get { return A.Count(); } }
}
You just need to set A and B, C will come out "on its own" based on the other two. Add null-checks and error handling as needed. In fact, C cannot be set at all in this sample, and it's correct because its value dependes on another property (here it's A).
Related
I dynamically set the type of an object
Then I want to query that object
int id = 123;
dynamic b =
Convert.ChangeType(dataToCompareTo, Type.GetType(tableName));
var values = (from item in (b)
where item.Id == id
select item).FirstOrDefault();
Linq will not allow me to do this ("query expressions with source type of dynamic [..] are not allowed"). I do not know the object type before runtime.
dynamic is the wrong thing to use here. ChangeType has a return type of object. It is not possible for the compiler to know at compile time what the type will be. If you define b as var the compiler will consider b to be an object and know nothing more about it.
Your LINQ expression seems to be expecting a particular type that implements IEnumerable and perhaps even an IEnumerable<SomeType>. In which case you would have to cast it to those types:
int id = 123;
var b =
Convert.ChangeType(dataToCompareTo, Type.GetType(tableName));
IEnumerable<SomeType> c = b as IEnumerable<SomeType>;
if (c == null)
{
///this is where you handle the objects that aren't what you need them to be for the linq expression below
}
else
{
var values = (from item in (c)
where item.Id == id
select item).FirstOrDefault();
}
If you want to use dynamic - you can do it here. Suppose you know that your b variable is list of some type which has Id property but you don't know which, and for whatever reason cannot use interface:
public class SomethingWithId {
public int Id { get; set; }
}
// you have no idea what that is at runtime
object something = new List<SomethingWithId>() {new SomethingWithId() {Id = id}};
Then you can use dynamic like this:
object something = new List<SomethingWithId>() {new SomethingWithId() {Id = id}};
// cast to `IEnumerable<dynamic>`, this will always compile
// but of course might fail at runtime, as always with dynamic
// in your case that is (IEnumerable<dynamic>) Convert.ChangeType(dataToCompareTo, Type.GetType(tableName));
var b = (IEnumerable<dynamic>) something;
// run your query
var values = (from item in b
where item.Id == id
select item).FirstOrDefault();
That said - don't get used to do such things in C# - it's strongly typed languge and you should not ignore benefits provided by that.
I know that in C# you can nowadays do:
var a = new MyObject
{
Property1 = 1,
Property2 = 2
};
Is there something like that in PHP too? Or should I just do it through a constructor or through multiple statements;
$a = new MyObject(1, 2);
$a = new MyObject();
$a->property1 = 1;
$a->property2 = 2;
If it is possible but everyone thinks it's a terrible idea, I would also like to know.
PS: the object is nothing more than a bunch of properties.
As of PHP7, we have Anonymous Classes which would allow you to extend a class at runtime, including setting of additional properties:
$a = new class() extends MyObject {
public $property1 = 1;
public $property2 = 2;
};
echo $a->property1; // prints 1
Before PHP7, there is no such thing. If the idea is to instantiate the object with arbitrary properties, you can do
public function __construct(array $properties)
{
foreach ($properties as $property => $value)
{
$this->$property = $value
}
}
$foo = new Foo(array('prop1' => 1, 'prop2' => 2));
Add variations as you see fit. For instance, add checks to property_exists to only allow setting of defined members. I find throwing random properties at objects a design flaw.
If you do not need a specific class instance, but you just want a random object bag, you can also do
$a = (object) [
'property1' => 1,
'property2' => 2
];
which would then give you an instance of StdClass and which you could access as
echo $a->property1; // prints 1
I suggest you use a constructor and set the variables you wish when initialising the object.
I went from c# to PHP too, so I got this working in PHP:
$this->candycane = new CandyCane(['Flavor' => 'Peppermint', 'Size' => 'Large']);
My objects have a base class that checks to see if there's one argument and if it's an array. If so it calls this:
public function LoadFromRow($row){
foreach ($row as $columnname=>$columnvalue)
$this->__set($columnname, $columnvalue);
}
It also works for loading an object from a database row. Hence the name.
Another way, which is not the proper way but for some cases okay:
class Dog
{
private $name;
private $age;
public function setAge($age) {
$this->age = $age;
return $this;
}
public function getAge() {
return $this->age;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
}
$dogs = [
1 => (new Dog())->setAge(2)->setName('Max'),
2 => (new Dog())->setAge(7)->setName('Woofer')
];
I have just a silly doubt that below is my small piece of code.
IDictionary<string, string> dic = new Dictionary<string, string>();
IDictionary<Demo, string> dic2 = new Dictionary<Demo, string>();
dic.Add("S1", "S1.1");
dic.Add("S1", "S1.1");
Demo d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "1");
d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "2");
So my question is i am getting exception at line no 4 which is correct according to dictionary concept that I can not add duplicate key in Dictionary however when I am trying to do same thing with object and object with same name I am not getting any exception event Dictionary have now two object of same type and same name.
Please help to understand this concept.
When inserting data into dictionary, Equals is used to check wheter key is unique.
In string Equals is implemented to check its value. That is why you cannot insert two strings into dictionary. What's more string is strange type - technically it is reference type, but acts like value type.
In bare object (or when not overriden), Equals is implemented to compare object by reference - it just checks wheter variabled points to the same area of memory (note: we are talking about classes, not structs :-)). So when you create two objects:
Demo d1 = new Demo() { MyProperty = 1 };
d1 = new Demo() { MyProperty = 1 };
There are two copies of that object in different place in memory, so Equals says: "That objects are different" - and you can add it to the dictionary.
You can of course change this behaviour by overriding Equals (and GetHashCode but here is skipped to keep answer clear) in Demo:
public override bool Equals(object obj)
{
// If parameter cannot be cast to Demo or is null return false.
Demo p = obj as Demo;
if (p == null)
{
return false;
}
// Return true if the fields match:
return (MyPropertyx == p.MyProperty));
}
Then:
Demo d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "1");
d1 = new Demo() { MyProperty = 1 };
dic2.Add(d1, "2");
will not definitely allow to insert second value.
In C# strings behave like value types which means that the value of the string is compared (which is called Value Equality), meaning:
var string1 = "S1";
var string2 = "S1";
Console.WriteLine(string1 == string2) // will output true
In the case of objects (such as your Demo object) by default when they are compared they are only checked to see if they are the same object (which is called Reference Equality), meaning:
var d1 = new Demo() { MyProperty = 1 };
var d2 = new Demo() { MyProperty = 1 };
Console.WriteLine(d1 == d2) // will output false
Now with objects you can implement Value Equality so that the above example will output true.
You can learn more about that with this guideline.
You have two objects using the same variable name (d1) but they refer to different instances of an object - so there is no duplicate.
It also looks like you expect both objects to be the "same" based on both having a property MyProperty with the value 1. This is not the case - the dictionary, by default, will use the references as the key, which are different as I mentioned above. To enable the dictionary to treat your two objects as the same you would need to override Equals and GetHashCode in your class Demo
I have function that accepts a Parameters of type List as follows:
private decimal CalculateIRR(List<AmortizationDepotResult> lstAmortizationDepotResult, decimal carryAmount)
{
if (lstAmortizationDepotResult.Count > 0)
{
var lstLoanDepots = lstAmortizationDepotResult.ToList();
lstLoanDepots.First().Payment = carryAmount;
In above code, i just want to change the parameter value(Payment) of first object in the list. if i execute above code, carryAmount value gets reflect in lstAmortizationDepotResult as wel as in lstLoanDepots also.
but i dont want to change value in lstAmortizationDepotResult, it should reflect only in lstLoanDepots.
so how do i solve my problem ???
Thanks..
Welcome to the world of objects, where your variables are not values but references. Thus:
var a = new Foo();
var b = a;
a.Bar = "Hello!";
Console.WriteLine(b.Bar); // output = "Hello!"
If you want to copy an object's values to another identical object in such a way that they do not share the same memory space, you'll have to do that explicitly:
var b = new Foo
{
Bar = a.Bar,
OtherField = a.OtherField
};
Enumerable.ToList creates a new list but all objects contained reference the original objects. If you want a deep copy of all objects in the list provide an appropriate constructor or intialize all properties manually.
if (lstAmortizationDepotResult.Count > 0)
{
var lstLoanDepots = lstAmortizationDepotResult
.Select(x=> new AmortizationDepotResult{
Payment = carryAmount,
Property2 = x.Property2, Property3 = x.Property3, ....
})
.ToList();
// ...
I'd implement IClonable interface in your AmortizationDepotResult class:
public class AmortizationDepotResult ...
IClonable {
...
Object IClonable.Clone() {
return Clone();
}
public AmortizationDepotResult Clone() {
AmortizationDepotResult result = new AmortizationDepotResult();
...
result.Payment = Payment;
...
return result;
}
}
So in order to have a deep copy you can do
private decimal CalculateIRR(List<AmortizationDepotResult> lstAmortizationDepotResult, decimal carryAmount) {
if (lstAmortizationDepotResult.Count > 0) {
var lstLoanDepots = lstAmortizationDepotResult
.Select(item => item.Clone())
.ToList();
lstLoanDepots[0].Payment = carryAmount;
...
}
i wants to assign column alias to another column in linq to sql select new keyword my code is
var query=from d in db.tblAttributeDatas
select new
{
a=d.strValue,
b=a
};
but compiler give me error.
can not resolved symbol a
.
You cannot use alias that way.
You have to do it using let this way:
var query=from d in db.tblAttributeDatas
let str = d.strValue // hold value here
select new
{
a=str, // now assign here
b=str
};
Basically, you can't do this because of the nature of object initializers (which is: initializing objects using the object literal notation { ... }).
This simple line of code...
var x = new { a = 1, b = 2 };
...is executed in IL code as...
<>f__AnonymousType0<System.Int32,System.Int32>..ctor
So you see that the anonymous type is created having a two-parameter constructor. Suppose this constructor would be visible as...
class X
{
public X(int a, int b) { }
}
It's obvious you can't call this constructor by
var x = new X(1, a);
You must supply two values. One constructor argument can't "borrow" the value of the other argument.
assign the same value to b .. there is no harm..
var query = from d in db.tblAttributeDatas
select new
{
a = d.strValue,
b = d.strValue
};