PHP struct initialization like in C# [duplicate] - c#

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')
];

Related

dynamic type does not contain a definition for 'property', error? [duplicate]

My situation is very simple. Somewhere in my code I have this:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
//How to do this?
if (myVariable.MyProperty.Exists)
//Do stuff
So, basically my question is how to check (without throwing an exception) that a certain property is available on my dynamic variable. I could do GetType() but I'd rather avoid that since I don't really need to know the type of the object. All that I really want to know is whether a property (or method, if that makes life easier) is available. Any pointers?
I think there is no way to find out whether a dynamic variable has a certain member without trying to access it, unless you re-implemented the way dynamic binding is handled in the C# compiler. Which would probably include a lot of guessing, because it is implementation-defined, according to the C# specification.
So you should actually try to access the member and catch an exception, if it fails:
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
try
{
var x = myVariable.MyProperty;
// do stuff with x
}
catch (RuntimeBinderException)
{
// MyProperty doesn't exist
}
I thought I'd do a comparison of Martijn's answer and svick's answer...
The following program returns the following results:
Testing with exception: 2430985 ticks
Testing with reflection: 155570 ticks
void Main()
{
var random = new Random(Environment.TickCount);
dynamic test = new Test();
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 100000; i++)
{
TestWithException(test, FlipCoin(random));
}
sw.Stop();
Console.WriteLine("Testing with exception: " + sw.ElapsedTicks.ToString() + " ticks");
sw.Restart();
for (int i = 0; i < 100000; i++)
{
TestWithReflection(test, FlipCoin(random));
}
sw.Stop();
Console.WriteLine("Testing with reflection: " + sw.ElapsedTicks.ToString() + " ticks");
}
class Test
{
public bool Exists { get { return true; } }
}
bool FlipCoin(Random random)
{
return random.Next(2) == 0;
}
bool TestWithException(dynamic d, bool useExisting)
{
try
{
bool result = useExisting ? d.Exists : d.DoesntExist;
return true;
}
catch (Exception)
{
return false;
}
}
bool TestWithReflection(dynamic d, bool useExisting)
{
Type type = d.GetType();
return type.GetProperties().Any(p => p.Name.Equals(useExisting ? "Exists" : "DoesntExist"));
}
As a result I'd suggest using reflection. See below.
Responding to bland's comment:
Ratios are reflection:exception ticks for 100000 iterations:
Fails 1/1: - 1:43 ticks
Fails 1/2: - 1:22 ticks
Fails 1/3: - 1:14 ticks
Fails 1/5: - 1:9 ticks
Fails 1/7: - 1:7 ticks
Fails 1/13: - 1:4 ticks
Fails 1/17: - 1:3 ticks
Fails 1/23: - 1:2 ticks
...
Fails 1/43: - 1:2 ticks
Fails 1/47: - 1:1 ticks
...fair enough - if you expect it to fail with a probability with less than ~1/47, then go for exception.
The above assumes that you're running GetProperties() each time. You may be able to speed up the process by caching the result of GetProperties() for each type in a dictionary or similar. This may help if you're checking against the same set of types over and again.
Maybe use reflection?
dynamic myVar = GetDataThatLooksVerySimilarButNotTheSame();
Type typeOfDynamic = myVar.GetType();
bool exist = typeOfDynamic.GetProperties().Where(p => p.Name.Equals("PropertyName")).Any();
Just in case it helps someone:
If the method GetDataThatLooksVerySimilarButNotTheSame() returns an ExpandoObject you can also cast to a IDictionary before checking.
dynamic test = new System.Dynamic.ExpandoObject();
test.foo = "bar";
if (((IDictionary<string, object>)test).ContainsKey("foo"))
{
Console.WriteLine(test.foo);
}
The two common solutions to this include making the call and catching the RuntimeBinderException, using reflection to check for the call, or serialising to a text format and parsing from there. The problem with exceptions is that they are very slow, because when one is constructed, the current call stack is serialised. Serialising to JSON or something analogous incurs a similar penalty. This leaves us with reflection but it only works if the underlying object is actually a POCO with real members on it. If it's a dynamic wrapper around a dictionary, a COM object, or an external web service, then reflection won't help.
Another solution is to use IDynamicMetaObjectProvider to get the member names as the DLR sees them. In the example below, I use a static class (Dynamic) to test for the Age field and display it.
class Program
{
static void Main()
{
dynamic x = new ExpandoObject();
x.Name = "Damian Powell";
x.Age = "21 (probably)";
if (Dynamic.HasMember(x, "Age"))
{
Console.WriteLine("Age={0}", x.Age);
}
}
}
public static class Dynamic
{
public static bool HasMember(object dynObj, string memberName)
{
return GetMemberNames(dynObj).Contains(memberName);
}
public static IEnumerable<string> GetMemberNames(object dynObj)
{
var metaObjProvider = dynObj as IDynamicMetaObjectProvider;
if (null == metaObjProvider) throw new InvalidOperationException(
"The supplied object must be a dynamic object " +
"(i.e. it must implement IDynamicMetaObjectProvider)"
);
var metaObj = metaObjProvider.GetMetaObject(
Expression.Constant(metaObjProvider)
);
var memberNames = metaObj.GetDynamicMemberNames();
return memberNames;
}
}
Denis's answer made me think to another solution using JsonObjects,
a header property checker:
Predicate<object> hasHeader = jsonObject =>
((JObject)jsonObject).OfType<JProperty>()
.Any(prop => prop.Name == "header");
or maybe better:
Predicate<object> hasHeader = jsonObject =>
((JObject)jsonObject).Property("header") != null;
for example:
dynamic json = JsonConvert.DeserializeObject(data);
string header = hasHeader(json) ? json.header : null;
Well, I faced a similar problem but on unit tests.
Using SharpTestsEx you can check if a property existis. I use this testing my controllers, because since the JSON object is dynamic, someone can change the name and forget to change it in the javascript or something, so testing for all properties when writing the controller should increase my safety.
Example:
dynamic testedObject = new ExpandoObject();
testedObject.MyName = "I am a testing object";
Now, using SharTestsEx:
Executing.This(delegate {var unused = testedObject.MyName; }).Should().NotThrow();
Executing.This(delegate {var unused = testedObject.NotExistingProperty; }).Should().Throw();
Using this, i test all existing properties using "Should().NotThrow()".
It's probably out of topic, but can be usefull for someone.
Following on from the answer by #karask, you could wrap the function as a helper like so:
public static bool HasProperty(ExpandoObject expandoObj,
string name)
{
return ((IDictionary<string, object>)expandoObj).ContainsKey(name);
}
For me this works:
if (IsProperty(() => DynamicObject.MyProperty))
; // do stuff
delegate string GetValueDelegate();
private bool IsProperty(GetValueDelegate getValueMethod)
{
try
{
//we're not interesting in the return value.
//What we need to know is whether an exception occurred or not
var v = getValueMethod();
return v != null;
}
catch (RuntimeBinderException)
{
return false;
}
catch
{
return true;
}
}
If you control the type being used as dynamic, couldn't you return a tuple instead of a value for every property access? Something like...
public class DynamicValue<T>
{
internal DynamicValue(T value, bool exists)
{
Value = value;
Exists = exists;
}
T Value { get; private set; }
bool Exists { get; private set; }
}
Possibly a naive implementation, but if you construct one of these internally each time and return that instead of the actual value, you can check Exists on every property access and then hit Value if it does with value being default(T) (and irrelevant) if it doesn't.
That said, I might be missing some knowledge on how dynamic works and this might not be a workable suggestion.
If your use case is to convert an api response, carrying about only a few fields, you can use this:
var template = new { address = new { street = "" } };
var response = JsonConvert.DeserializeAnonymousType(await result.Content.ReadAsStringAsync(), template);
string street = response?.address?.street;
Here is the other way:
using Newtonsoft.Json.Linq;
internal class DymanicTest
{
public static string Json = #"{
""AED"": 3.672825,
""AFN"": 56.982875,
""ALL"": 110.252599,
""AMD"": 408.222002,
""ANG"": 1.78704,
""AOA"": 98.192249,
""ARS"": 8.44469
}";
public static void Run()
{
dynamic dynamicObject = JObject.Parse(Json);
foreach (JProperty variable in dynamicObject)
{
if (variable.Name == "AMD")
{
var value = variable.Value;
}
}
}
}
In my case, I needed to check for the existence of a method with a specific name, so I used an interface for that
var plugin = this.pluginFinder.GetPluginIfInstalled<IPlugin>(pluginName) as dynamic;
if (plugin != null && plugin is ICustomPluginAction)
{
plugin.CustomPluginAction(action);
}
Also, interfaces can contain more than just methods:
Interfaces can contain methods, properties, events, indexers, or any
combination of those four member types.
From: Interfaces (C# Programming Guide)
Elegant and no need to trap exceptions or play with reflexion...
I know this is really old post but here is a simple solution to work with dynamic type in c#.
can use simple reflection to enumerate direct properties
or can use the object extention method
or use GetAsOrDefault<int> method to get a new strongly typed object with value if exists or default if not exists.
public static class DynamicHelper
{
private static void Test( )
{
dynamic myobj = new
{
myInt = 1,
myArray = new[ ]
{
1, 2.3
},
myDict = new
{
myInt = 1
}
};
var myIntOrZero = myobj.GetAsOrDefault< int >( ( Func< int > )( ( ) => myobj.noExist ) );
int? myNullableInt = GetAs< int >( myobj, ( Func< int > )( ( ) => myobj.myInt ) );
if( default( int ) != myIntOrZero )
Console.WriteLine( $"myInt: '{myIntOrZero}'" );
if( default( int? ) != myNullableInt )
Console.WriteLine( $"myInt: '{myNullableInt}'" );
if( DoesPropertyExist( myobj, "myInt" ) )
Console.WriteLine( $"myInt exists and it is: '{( int )myobj.myInt}'" );
}
public static bool DoesPropertyExist( dynamic dyn, string property )
{
var t = ( Type )dyn.GetType( );
var props = t.GetProperties( );
return props.Any( p => p.Name.Equals( property ) );
}
public static object GetAs< T >( dynamic obj, Func< T > lookup )
{
try
{
var val = lookup( );
return ( T )val;
}
catch( RuntimeBinderException ) { }
return null;
}
public static T GetAsOrDefault< T >( this object obj, Func< T > test )
{
try
{
var val = test( );
return ( T )val;
}
catch( RuntimeBinderException ) { }
return default( T );
}
}
As ExpandoObject inherits the IDictionary<string, object> you can use the following check
dynamic myVariable = GetDataThatLooksVerySimilarButNotTheSame();
if (((IDictionary<string, object>)myVariable).ContainsKey("MyProperty"))
//Do stuff
You can make a utility method to perform this check, that will make the code much cleaner and re-usable

Issue related to make a copy of List variable in C#

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;
...
}

How to reuse LINQ Select Expression with arguments

I write a LINQ query and for Select clause I created an Expression to reuse it.
My query looks like this
DataContext.Single.Select(SearchSelector).ToList();
Where as Search Selector defined as
private Expression<Func<Singles, SearchSingles>> SearchSelector = s =>
new SearchSingles
{
};
The above works fine, but what if I want to use two input parameters? How would I invoke it?
private Expression<Func<Singles,string, SearchSingles>> SearchSelector = (s,y) =>
new SearchSingles
{
};
Rather than having a field that stores the expression, have a method that creates the expression that you need given a particular string:
private static Expression<Func<Singles, SearchSingles>> CreateSearchSelector(
string foo)
{
return s =>
new SearchSingles
{
Foo = foo,
};
}
You can then use this method like so:
DataContext.Single.Select(CreateSearchSelector("Foo")).ToList();
what about leaving the signature alone and passing additional parameters as captured values? It might have limited use as an initialized member variable, like this, but if you assign from within some worker function, rather than initialize it during class construction you'd have more power.
private Func<Singles, SearchSingles> SearchSelector = s =>
new SearchSingles
{
someVal = capturedVariable,
someOther = s.nonCapturedVar
};
that would work if capturedVariable were a static member
or
private Func<Singles, SearchSingles> SearchSelector = null;
private void WorkerFunction(string capturedVariable, bool capAgain, bool yetAgain)
{
SearchSelector = s => {
bool sample = capAgain;
if (capturedTestVar)
sample = yetAgain;
return new SearchSingles
{
someVal = capturedVariable,
someOther = s.nonCapturedVar,
availability = sample
};
};
};
you could have all sorts of fun
*EDIT* references to Expression removed and clarifications

How can I initialize an instance of AttributeCollection?

I'm trying to initialize an AttributeCollection but I seem to get no good suggestions from Google with this search.
I'm also open to create the object using the specialized constructor that takes an array of type Attribute as described here on MSDN but I can't find any examples for that either.
I can resolve the issue by adding each attribute on its own as shown below but that's not as nice as initializing it directly.
bzzz["prop1"] = "val_1";
bzzz["prop2"] = "val_2";
...
bzzz["prop8"] = "val_8";
bzzz["prop9"] = "val_9";
It's the class in System.ComponentModel.
This is perfectly legal:
var attributes = new AttributeCollection();
attributes.Add("key1", "value1");
attributes.Add("key2", 2);
attributes.Add("key3", new EntityReference("contact", Guid.NewGuid()));
var entity = new Entity(){ Attributes = attributes };
Edit
You can do it all in one C# statement, At one time I saw it as being less readable, but now I see it being more readable so it really comes down to either picking an existing standard, or personal choice:
var entity = new Entity()
{
Attributes = new AttributeCollection() {
{ "key1", "value1" },
{ "key2", 2 },
{ "key3", new EntityReference("contact", Guid.NewGuid())}
}
};
Let's say I have a simple attribute
public class SimpleAttribute : Attribute
{
public SimpleAttribute(String val)
{
value = val;
}
protected String value;
}
I would add Attributes to the AttributeCollection like this.
AttributeCollection attrColl = new AttributeCollection(
new SimpleAttribute("value1"), new SimpleAttribute("value2"));
The only constructor parameter is declared as params, so you can pass multiple attributes (separated by commas), while you are constructing the collection.

How to return Generic.List<Anonymoustype> from a function in C#

ASP.NET 3.5 C#
I am joining two tables using Linq.
Table names are MapAssets and ExitPoint.
In Database they are related with 'has a relationship'
I am writing a function in my BLL to return the joined table
public List<ExitPoints> GetExitPointDetailsByProjectID(int iProjectID)
{
ctx = new CoreDBDataContext();
var exitPointDetails = from ma in ctx.MapAssets
join ep in ctx.ExitPoints
on ma.MapAssetID equals ep.MapAssetID
where ma.ProjectID == iProjectID
select new
{
//would like to have data from both tables here
ctx.MapAssets,
ctx.ExitPoints
};
return exitPointDetails.ToList();
}
This obviuosly doesn't work. And I dont know what to return at all.
All constraint I have for the return is to be able to be bound to a gridview.
is this the correct way? Or else whats the correct way?
You can't, or better, the only way is to return them boxed in a List of object, but this hugely complicates things, because you can't cast them to any type (of course it's anonymous) and you can only access their properties through reflection....
In cases like that, I'd highly suggest you to create a custom class.
EDIT:
On a side note...
If you were using .net 4, things would be easier because you could returns dynamic Type instead of object (look at this link to see dynamic's simplifications), but I'd prefer to create a custom class anyway.
Have a look at how to return anonymous types from Method.
http://forums.asp.net/t/1387455.aspx.
Copying the code from the link.
object ReturnAnonymous()
{
return new { Name="Faisal", City="Chakwal" };
}
// Application entry-point
void Main()
{
object o = ReturnAnonymous();
// This call to 'Cast' method converts first parameter (object) to the
// same type as the type of second parameter - which is in this case
// anonymous type with 'Name' and 'City' properties
var typed = Cast(o, new { Name="", City="" });
Console.WriteLine("Name={0}, City={1}", typed.Name, typed.City);
}
// Cast method - thanks to type inference when calling methods it
// is possible to cast object to type without knowing the type name
T Cast<T>(object obj, T type)
{
return (T)obj;
}
You can use the method mentioned below to return List and
List<object> lstAnonymousTypes = GetExitPointDetailsByProjectID(1);
foreach(object o in lstAnonymousTypes)
{
//Change it accordingly
var typed = Cast(o, new { new MapAssets() , new ExitPoints() });
}
Hope this helps not tried.
You can't return an anonymous type, you can only use an anonymous type in the scope of the method it's in. You could need to create a new class with MapAssets/ExitPoints properties and select a new instance of that class.
You are trying to return List ExitPoints and List of MapAssets which is not possible because you are getting the output from both tables ie ExitPoints and MapAssets. And it is also not possible to return an anonymous type. So in order to retrun the query create a class name ExMapClass with properties that you need as output of the queries. Now after executing the linq query which you have written iterate it ie
create list of newly created class
list newclass = new list ();
foreach( var result in ctx )
{
instantiate the created class
obj.Property1 = var.MapAssets;
obj.Property2 = var.ExitPoints;
newclass.add(obj);
}
now retrun the list of newlycreated class.
hope you got it.
Do you have to bind to this object after you've created it? If not then you can create an "persistent AnonymousType" class that stores the values in a dictionary and returns the property values with a method like:
string lastName AnonType.GetValue<string>("LastName");
int age AnonType.GetValue<int>("Age");
Here is a link to an excellent example. The author also has an example where he creates the "AnonymousType" from a datatable.
I have worked on a variation of this where I provide the ability to query a list of "AnonymousType" with the following syntax:
// Here's the query
var dept13 = anonAgents.AsQueryable()
.Where(x => x.Has("Department", Compare.Equal, 13);
// Here is how the List is constructed
private static AnonymousType ProvisionAgent(string name, int department)
{
return AnonymousType.Create(new
{
Name = name,
Department = department
});
}
private List<AnonymousType> CreateAnonAgentList()
{
var anonAgents = new List<AnonymousType>();
// Dave and Cal are in Department 13
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Dan Jacobs", 13, 44)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Calvin Jones", 13, 60)));
// Leasing = Dept 45
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stanley Schmidt", 45, 36)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Jeff Piper", 45, 32)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stewart Blum", 45, 41)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Stuart Green", 45, 38)));
// HR = Dept 21
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Brian Perth", 21, 25)));
anonAgents.Add(AnonymousType.Create(CreateAgentAnonType("Katherine McDonnel", 21, 23)));
return anonAgents;
}
Just use and ArrayList
public static ArrayList GetMembersItems(string ProjectGuid)
{
ArrayList items = new ArrayList();
items.AddRange(yourVariable
.Where(p => p.yourProperty == something)
.ToList());
return items;
}
wont this work ?
ctx = new CoreDBDataContext();
var exitPointDetails = from ma in ctx.MapAssets
join ep in ctx.ExitPoints
on ma.MapAssetID equals ep.MapAssetID
where ma.ProjectID == iProjectID
select Tuple.Create(ma, ep);
return exitPointDetails.ToList();

Categories

Resources