I have a class that looks something like this:
public class MyClass {
public string id { get; set; }
public string Id { get; set; }
public string SomethingMore {get; set;}
}
I don't control the class. So I have to live with the fact that both id (lowercase i) and Id (uppercase I) exist. Like it or not, I cannot change this, hence this answer answers my why, but it does not answer my how-to question.
In my Expression tree I have:
var newExpression = Expression.New(typeof(MyClass).GetConstructor(Type.EmptyTypes))
var propertyExpression = Expression.Property(newExpression, "Id");
The second line throws an Ambiguous Match Exception, because Expression.Property(..) is case insensitive - e.g. Expression.Property(newExpression, "SomethingMore") does not throw an exception.
What sort of work-around options do I have?
The next step in the code is:
Expression.Assign(propertyExpression, Expression.Constant("someNewValue", typeof(string));
I don't need to assign value to the id property and I know the meaning of id, which is special. I do however need to be able to assign a value to the Id property.
I guess I could create a derived version of my MyClass, that doesn't include the id property, but I need to do this at run-time. If this is the solution, how can it be done? Or, maybe there's a much better solution?
I don't control the MyClass. I only know that a developer would be inclined to define both idand Id in their class.
There are overloads for Expression.Property that allow a more explicit means of accessing the desired property.
Get the property info explicitly using reflection and use that.
var type = typeof(MyClass);
var newExpression = Expression.New(type.GetConstructor(Type.EmptyTypes));
PropertyInfo property = type.GetProperty("Id");
var propertyExpression = Expression.Property(newExpression, property);
Related
Say I have this class with a few members, for example (this is a contrived example, I'd rather no have a discussion about the intricacies of the real-life design. I really just want to convey the general idea here.):
public class Address
{
public Guid Id { get; set; }
public Guid? HouseId { get; set; }
public Guid? FlatId { get; set; }
public Guid? SomeOtherBuildingTypeId { get; set;
}
Now as it happens there exist 3 methods to create an Address:
public void CreateAddressForHouse();
public void CreateAddressForFlat();
public void CreateAddressForSomeOtherBuildingType();
Under the surface this group of methods does the exact same thing, bar setting a different Id property in the Address class. This is causing quite some code duplication in the real life application and I want to rewrite this to something more general.
In my mind I can pass the name of the required property and its value to a CreateAddress function, in something like a Func. But I'm seriously lacking in this respect, where to start? What .NET stuff can I use out of the box? Or what specific keywords should I look for?
You can use a MemberExpression:
public void CreateAddress(Expression<Func<Address, Guid?>> member)
{
// Get the property from the expression
var propertyInfo = GetPropertyInfo(this, member);
// Create a new address
var guid = Guid.NewGuid();
// Assign it to the property of this instance
propertyInfo.SetValue(this, guid);
}
Then you call the method like this, using a lambda a => a.PropertyName:
var address = new Address();
address.CreateAddress(a => a.HouseId);
Console.WriteLine(address.HouseId);
See Retrieving Property name from lambda expression for the implementation of GetPropertyInfo. It gets the PropertyInfo of the member specified in the lambda expression (and checks that it is indeed a property), which you can use to set the property in the CreateAddress method.
Apart from that, #Corak's suggestion is a valid one. Maybe you shouldn't use a property per address type, but use a Dictionary<AddressType, Guid?> property. That may or may not be viable depending on the class design and its intended usage.
You can use expression trees to simplify your problem:
public class AddressService
{
public Address CreateAddress(Expression<Func<Address, Guid?>> idPropertySelector)
{
// So you get the property info to later set it using reflection
MemberExpression propertyExpr = (MemberExpression)idPropertySelector.Body;
PropertyInfo property = (PropertyInfo)propertyExpr.Member;
// Then you create an instance of address...
Address address = new Address();
// and you set the property using reflection:
property.SetValue(address, (Guid?)Guid.NewGuid());
return address;
}
}
Now, who knows where in your code, this will work:
AddressService service = new AddressService();
Address address = service.CreateAddress(a => a.FlatId);
Guid? flatId = address.FlatId; // This will be already assigned!
You can add a property BuildingType BuildingType being a value of the enum BuildingType { House, Flat, SomeOtherBuildingType, YetAnotherThing } as suggested by Corak.
To make it simpler, you can create a parameterized constructor in Address class:
public Address(Guid? id,BuildingType type)
{
switch(type)
{
case BuildingType.House:
HouseId=id;
break;
case BuildingType.Flat:
FlatId=id;
break;
case BuildingType.SomeOtherBuildingType:
SomeOtherBuildingTypeId =id;
break;
default:
break;
}
}
This way it will be easier to extend.
Also, you need not to have so many methods. Only one CreateAddress() can be used to generate address of multiple types.
I have an extension method that I use attempt to extract some metadata from an object, such as this:
public static string ToTypeName(this object obj)
{
string name;
var asType = obj.GetType();
if (Attribute.IsDefined(asType, typeof(DataMemberAttribute)) || Attribute.IsDefined(asType, typeof(DataContractAttribute)))
{
var attrName = obj.GetType().GetCustomAttributes(typeof(DataContractAttribute), true).SingleOrDefault() as DataContractAttribute;
name = string.IsNullOrEmpty(attrName.Name) ? asType.Name : attrName.Name;
}
else
{
name = asType.Name;
}
return name;
}
I'm currently using it to scrap metadata from objects that are decorated with various attributes. In this example, it is looking for the DataContractAttribute and then pulling the value from the Name property. This works fine.
However, there are times when that object is of the PropertyInfo type. What is happening is that the Attribute.IsDefined is testing true, thus entering the block to be scraped, however, it is failing to cast so attrName is coming out null.
I added this block before the previous block:
if (obj is PropertyInfo)
{
var asPropInfo = obj as PropertyInfo;
if (Attribute.IsDefined(asPropInfo, typeof(DataMemberAttribute)) || Attribute.IsDefined(asPropInfo, typeof(DataContractAttribute)))
{
var attrName = asPropInfo.GetType().GetCustomAttributes(typeof(Attribute), true).SingleOrDefault();
if (attrName is DataMemberAttribute)
{
var attr = attrName as DataMemberAttribute;
name = string.IsNullOrEmpty(attr.Name) ? asType.Name : attr.Name;
}
else if (attrName is DataContractAttribute)
{
var attr = attrName as DataContractAttribute;
name = string.IsNullOrEmpty(attr.Name) ? asType.Name : attr.Name;
}
}
}
the IsDefined check is still testing true, but still failing to cast. I looked at the CustomAttributes property of obj (as it enters the method) via watch variables and it shows 1 attribute of type DataContractAttribute, however, by the time i get to asPropInfo.GetType(), it has changed to Serializable.
It could be that i've been at this for too long and I'm not thinking clear, but does anyone have any input?
UPDATE:
I was able to remove the GetType() and just call GetCustomAttributes() directly, however, the result is still not what I need. Here's what appears to be happening:
Imagine a Person class contains a member of type Person like so:
[DataContract(Name = "Employee")]
public class PersonDto{
public string FirstName {get;set;}
public string LastName {get;set;}
[DataMember(Name = "Boss")]
public Person Supervisor {get;set;}
}
What is happening during the scrape is that Supervisor is getting passed in as PropertyInfo along with it's DataMember attribute, and my extension is reading it and returning "Boss," and this totally makes sense. However, what I actually need at this stage is the DataContractattribute and here's why:
When the Supervisor property gets serialized, it will serialize as "Boss" and I need to know that, so I save that to a DTO. However, I also need to know that "Boss" is of the serialized "type" which is "Employee". This might seem weird, but makes sense in the end lol. I'm using this to help generate help documentation for our API. Internally, the class type might be "PersonDto", but the type that is displayed to the client is "Employee". So in terms of help documentation, the developer knows that there's a "Boss" element, but they also need to know that it is simply an instance of "Employee" (as far as they're concerned), so that they can look up documentation for that object. Does that makes sense?
I believe you don't need to call GetType on asPropInfo. Try that:
var attrName = asPropInfo.GetCustomAttributes(typeof(Attribute), true).SingleOrDefault();
This seems like a simple question, but for some reason I can't find the answer anywhere. Basically, I'd like to be able to implement a constructor that takes NamedParameters.
By named parameters, I do not mean parameters with default values (optional parameters) such as:
public SomeMethod(){
string newBar = Foo(bar2 : "customBar2");
}
public string Foo(string bar1 = "bar1", bar2 = "bar2" ){
//...
}
A good example of what I'm trying to achieve is the AuthorizeAttribute from the System.Web.Mvc assembly. Which you can use the following way:
[Authorize(Roles = "Administrators", Users = "ThatCoolGuy")]
public ActionResult Admin(){
}
The constructor's signature in intellisense looks like the following example and I believe (please confirm) that those NamedParameters are mapping to class properties.
AuthorizeAttribute.AuthorizeAttribute(NamedParameters...)
Initiliaze new instance of the System.Web.Mvc.AuthorizeAttribute class
Named parameters:
Order int
Users string
Roles string
Please note:
The syntax of defining the parameter name when calling a method has nothing to do with optional parameters:
You can use Foo(bar1 : "customBar1"); even if Foo is declared like this: void Foo(string bar1)
To answer the question:
My guess is that this is syntactic sugar similar to the object initializers introduced in Visual Studio 2010 and therefore you can't use this for your own classes.
The behaviour you are talking about is specific for attributes and cannot be reused in "normal" classes constructors.
You don't need to "implement" anything.
The parameters can be used in the manner you describe just by existing as parameters on the constructor.
You do need to be using C# 3.5 or above, when they were introduced.
Your example will compile and run on C# 4.0 / Visual Studio 2010 without modification.
See Named and Optional Arguments (C# Programming Guide) on MSDN.
In regards to properties on the object, that do not have a corresponding constructor arguments, the exact syntax is specific to attributes and can't be replicated, though, with object initializers you can get close.
You can use the builder/constructor info pattern together with property initializers.
class PersonInfo
{
public string Name { get; set; }
public int? Age { get; set; }
public Color? FavoriteColor { get; set; }
public Person BuildPerson()
{
return new Person(this);
}
}
class Person
{
public Person(PersonInfo info)
{
// use info and handle optional/nullable parameters to initialize person
}
...
}
var p = new Person(new PersonInfo { Name = "Peter", Age = 15 });
// yet better
var p = new PersonInfo { Name = "Peter", Age = 15 }.BuildPerson();
I however don't understand, why you don't just use named parameters and provide null for indicating optional parameters.
class Person
{
public Person(string name = null, int? age = null, Color? favoriteColor = null) { /* ... */ }
}
var p = new Person(name: "Peter", age: 15);
Named parameters are NOT specific to attributes. It's a language syntax that can be used everywhere. It's fine to use properties for initialisers but you don't always want to have internals set as set properties.
Just instantiate you class using:
TheClass c = new Theclass(param3:firstValue, param1:secondValue, param2:secondValue);
With regards to this part of the question:
"I however don't understand, why you don't just use named parameters and provide null for indicating optional parameters."
The reason named parameters are nice is you don't need to provide extraneous values in parentheses, just what you want to specify, because if it's optional you shouldn't even need to put null. Furthermore, if you specify null, you are overriding any default value for that parameter which makes it optional. Being optional implies there's a default value meaning nothing passed in.
Property initialisation at instance time is purely there for convenience. Since C there has been the ability to initialise values at construction time on types. Which is handy if those values can't be specified in the constructor. I personally feel that the convenience of them has spoiled people and it get a little too liberal and make everything public get AND set. Just depends on the design and security of properties you need.
I doubt that's possible. This is something specific for attributes.
I think the closest option is to use an object initializer:
class Foo {
public string Name {get;set;}
public int Data {get;set;}
}
var foo = new Foo {Name = "MyName", Data = 12};
try to use this signature
[AttributeUsage(AttributeTargets.Class)]
before the name of your class
Please refer to MSDN specification for full description:
https://msdn.microsoft.com/en-us/library/aa664614(v=vs.71).aspx
"Each non-static public read-write field and property for an attribute class defines a named parameter for the attribute class".
Visual C# 2010 introduces named and optional arguments. Named argument able you to specify an argument for a particular parameter by associating the argument with the parameter's name rather than with the parameter's position in the parameter list.Named arguments free you from the need to remember or to look up the order of parameters in the parameter lists of called methods.
static void Main(string[] args)
{
mapingFunction(snum2: "www.stackoverflow.com", num1: 1);
}
public static void mapingFunction(int num1, string snum2)
{
Console.WriteLine(num1 + " and " + snum2);
}
here you can see that argument are passed with our their order
What you probably want to do is implement public properties in your attribute:
public class AuditFilterAttribute : ActionFilterAttribute
{
public string Message { get; set; }
public AuditFilterAttribute() { }
}
They can be accessed through Named Parameters where you apply it:
[AuditFilter(Message = "Deleting user")]
public ActionResult DeleteUser(int userId)
Hope that helps...
I am trying to update public parameters of a known type MyClass from a NameValueCollection (see code below). This is possible in MVC3, the Controller class has an UpdateModel method which does exactly this with the Request.Params. I would like to do this outside of the Controller though.
Any thoughts?
public class MyClass
{
public string MyParam { get; set; }
}
...
var values = new NameValueCollection() { { "MyParam", "any string value for my param" } };
var myInstance = new MyClass();
Update(myInstance, values);
Cheers,
T
You should use reflection to perform this task:
This code is provided without proper validation, and it should be put into a method.
var type = myInstance.GetType();
foreach(var keyValue in values)
{
type.InvokeMember(keyValue.Key,BindingFlags.SetProperty,null,myInstance, new object[]{keyValue.Value});
}
There could be an error in this code, but even if it's the case, the general idea is here.
2 remarks: This code will fail miserably if the property doesn't exist on MyClass, or if the property type cannot be assigned from a string. It would therefore require proper validation (I know, I am repeating myself ).
You could use expression tree to perform the job too, particularly if you are setting a lot of values on the same known type, as expression trees can be compiled.
Does NewExpression.Members inform the LINQ runtime how to map a type's constructor parameters to its properties? And if so, is there an attribute to set the mapping? I'm imagining something like this:
public class Customer
{
public Customer(int id, string name)
{
Id = id;
Name = name;
}
[CtorParam("id")]
public int Id { get; set; }
[CtorParam("name")]
public string Name { get; set; }
}
But none of the MSDN docs really inform you how exactly Members is initialized.
My limited understanding is that you don't usually need to pass the member information; the arguments are taken (by position) from the arguments parameter. The member info is (I suspect) intended to help some internal APIs when dealing with things like anonymous-types, which look (in C#) like they are initialized by member (like an object-initializer), but which are actually initialized by constructor. This means things like LINQ-to-SQL will see a constcutor use, and then (in the next part of the query) access to obj.Name - it needs a way to understand that this means "the 3rd parameter to the constructor (which never actually gets called). In particular for things like groupings.
So this is fine:
var param = Expression.Parameter(typeof(string), "name");
var body = Expression.New(typeof(Customer).GetConstructor(new[] {typeof(int), typeof(string)}),
Expression.Constant(1), param);
var func = Expression.Lambda<Func<string, Customer>>(body, param).Compile();
var cust = func("abc");
If you do need them, I would expect them to be positional relative to the "arguments" expressions - so you would pass in (in an array) the member for id and name. Note that there is also a separate expression for intialzer-style binding.