I have 2 classes Customer an开发者_开发技巧d Person(share exactly the same properties and these properties should be filled in by a request
I would like to write a generic method like
//Usage Customer myCustomer =CreateCustomerOrPerson<Customer>(myRequest)
//Usage Person myPerson =CreateCustomerOrPerson<Person>(myRequest)
public static T FillPropertiesOfCustomerOrPerson<T>(Request request)
{
//not sure how I would I do it to fill the properties.
// T a = default(T);
//a.Name=request.Name;
//a.Surname=request.Surname;
// if (a is Customer)
//{
//?
/// }
return (T)a;
}
How would you write this generic method to avoid having 2 methods (one for customer and one for person)?
Edit
I have no control over these classes. I just need to fill the properties and I was wondering if I could write a generic method rather than 2 specific ones.
Given the requirements, your options are somewhat limited. If you don't want to make use of the dynamic
keyword (due to .NET version or whatever), you could do this old-style and use reflection. A possible implementation of that follows:
private const string PROP_NAME = "Name";
private const string PROP_SURNAME = "Surname";
public static T FillPropertiesOfCustomerOrPerson<T>(Request request)
where T : new()
{
if (typeof(T) != typeof(Person) && typeof(T) != typeof(Customer))
{
throw new Exception(
string.Format("{0} is not a supported type.", typeof(T).Name)
);
}
PropertyInfo name = typeof(T).GetProperty(PROP_NAME);
PropertyInfo surname = typeof(T).GetProperty(PROP_SURNAME);
T t = new T();
name.SetValue(t, request.Name, null);
surname.SetValue(t, request.Surname, null);
return t;
}
Optionally, you could remove the where T : new()
and replace the instantiation code with something like this:
T t = (T)Activator.CreateInstance(typeof(T));
+1 for CodeInChaos.
You should put the responsibility for reading properties from Request with the classes that have the properties. The best way would be to have either a base class or an interface that provides you with, let's say, a FillProperties method that takes a Request. Then put a restriction on T for your method that specifies the base class or interface and call T.FillProperties(request).
If you can't fix the design, I'd use duck typing instead. C# 4 has the dynamic
keyword. You'll lose type safety, and refactoring support, but at least you don't repeat yourself.
public static void FillPropertiesOfCustomerOrPerson(dynamic person, Request request)
{
person.Name=request.Name;
person.Surname=request.Surname;
}
Have Person
and Customer
either inherit from a base class (e.g. Customer : Person
) or implement a common interface. You can then just have your method accept the base type instead:
public static Person FillPropertiesOfPerson(Request request)
{
Person returnValue = new Person();
returnValue.Name = request.Name;
// etc...
return Person;
}
Note that if Person
and Customer
are partial classes (for example the proxy classes generated when you consume a web service) then you can use a partial-ness of these classes to do this:
// Define your interface to match the properties which are common to both types
interface IPerson
{
string Name
{
get;
set;
}
}
// Then use partial declarations like this (must be in the same namespace as the generated classes)
public partial class Person : IPerson { }
public partial class Customer : IPerson { }
This will only work if Person
and Customer
declare exactly the same properties (and are partial classes obviously!), however if there are some slight mismatches then you can use your partial definition to do some "fudging."
Failing that the only method I'm aware of is to use reflection to set the properties, however this isn't typesafe, would incur some performance penalties and is all round not a great idea (I'd probably rather write two identical methods than resort to reflection for something like this).
精彩评论