I have the following code, I want to refactor the duplication out of:
public bool HasBia
{
get
{
if (IsC2User())
{
return true;
}
if(_hasBia == null)
{
_hasBia = _excludes.HasBia;
}
return _hasBia.Value;
}
}
public bool HasTeachAndTest
{
get
{
if (IsC2User())
{
return true;
}
if(_hasTeachAndTest == null)
{
_hasTeachAndTest = _excludes.HasTeachAndTest;
}
return _hasTeachAndTest.Value;
}
}
The bit I am having trouble with is that, _excludes.HasBia and _excludes.HasTeachAndTest are dynamic expressions or dynamic properties that are resolved by TryGetMember of a class that inherits from DynamicObject.
I think I want to do something like this:
public bool HasPermission(bool? value, DynamicExpression expression)
{
if (IsC2User())
{
return true;
}
}
Then I can call it like this:
return HasPermission(_hasBia, _excludes.HasTeachAndTest);
But I am unsure how to invoke the expression when it is passed into the HasPermission method.
Anybody got any ideas?
Perhaps this would work.
public bool HasPermission(ref bool? field, bool defaultValue)
{
if (IsC2User())
{
return true;
}
if (field == null) //lazy loading a bool? overkill? :)
{
field = defaultValue;
}
return field;
}
//usage
public bool HasBia
{
get
{
return HasPermission(ref _hasBia, _excludes.HasBia);
}
}
Or if there are side effects of retrieving the default value
public bool HasPermission(ref bool? field, Func<bool> getDefaultValue)
{
if (IsC2User())
{
return true;
}
if (field == null)
{
field = getDefaultValue();
}
return field;
}
//usage
public bool HasTeachAndTest
{
get
{
return HasPermission(ref _hasTeachAndTest, () => _excludes.HasTeachAndTest);
}
}
I don't think it makes any sense to remove this sort of duplication, consider the additional complexity introduced by any of the possible solutions vs. the simplicity of repeating a pattern at two places.
Perhaps what you are really missing is a concept in your problem domain that you are trying to come by with duplication in your solution domain. Jeff M's solution is fine in regards to a technical implementation, but I'd not use it in this simple case.
Related
I keep running across the need for the same pattern in my code, which frequently needs to validate the values of all the properties in an object. The pseudo code looks like this:
bool ValidateMe(object c) {
var properties = GetProperties(c);
foreach (var property in properties) {
var value = property.GetValue(c);
if (!IsValid(value)) {
return false;
}
}
return true;
}
bool IsValid(int value)
{
return value != int.MaxValue;
}
bool IsValid(double value)
{
return value != double.MaxValue;
}
bool IsValid(object value)
{
return value != null;
} // etc.
I want the code to dynamically dispatch the value to the correct method based on the object's Type (which can be found by calling property.PropertType or value.GetType() assuming value is not null).
The only way I have found to make this work is something like this:
interface IValidator {
bool IsValid(object value);
}
class PredicateValidator<T> : IValidator {
private Predicate<T> method;
PredicateValidator(Predicate<T> method) {
this.method = method;
}
bool IsValid(object value) {
return IsValid((T) value);
}
bool IsValid(T value) {
return method.invoke(value);
}
}
var validationsByType = new Dictionary<Type,IValidator>();
validationsByType[typeof(double)]=new PredicateValidator<double>(IsValid);
validationsByType[typeof(double)]=new PredicateValidator<int>(IsValid);
and then the Map enables dispatching the object to correct method by type:
object value = property.GetValue(c);
bool result = validationsByType[c.GetType()].IsValid(value);
Is there native C# (i.e. language feature) for doing this dynamic dispatch by Type at runtime?
The dynamic keyword will do the downcast correctly. So the above code change be changed to:
bool ValidateMe(object c) {
var properties = GetProperties(c);
foreach (var property in properties) {
var value = property.GetValue(c);
if (!IsValid((dynamic) value)) {
return false;
}
}
return true;
}
bool IsValid(int value)
{
return value != int.MaxValue;
}
bool IsValid(double value)
{
return value != double.MaxValue;
}
The .NET Runtime then searches for the most specific method signature to invoke. I had previously thought that dynamic only worked for Duck Typing, but it also works for dynamic dispatch to overloaded methods.
Your approach is good if you want to keep a "nominal reflection execution".
My recommandation is to avoid reflection as "normal" execution code.
It cause the need to work with extremely abstract objects (often System.Object).
You can always use generic and/or reflection to produce on "fire/init time" a delegate adapted to your need without any Type resolution in "nonimal execution" and use the delegate naturally.
a short example to illustrate it
static public Validation
{
//Simply call the delegate (generic method is easier to use than generic class)
static public bool Validate<T>(T value)
{
return Validation<T>.Validate(value);
}
}
Implementation of the delegate
static public Validation<T>
{
static public readony Fun<T, bool> Validate;
static Validation
{
if (typeof(T) == typeof(string))
{
Validation<T>.Validate = new Func<T, bool>(value =>
{
var _string = (string)(object)value;
//Do your test here
return true;
});
}
else if (typeof(T) == typeof(int))
{
Validation<T>.Validate = new Func<T, bool>(value =>
{
var _int32 = (int)(object)value;
//Do your test here
return true;
});
}
//...
else if (typeof(T).IsClass)
{
var validate = typeof(Validation).GetMethod("Validate");
var parameter = Expression.Parameter(typeof(T));
var properties = typeof(T).GetProperties();
if (properties.length < 0)
{
Validation<T>.Validate = new Func<T, bool>(value => true);
}
else
{
var body = Expression.Constant(true);
foreach (var property in properties)
{
body = Expression.Condition(Expression.Call(validate.MakeGenericMethod(property.PropertyType), parameter), body, Expression.Constant(false));
}
Validation<T>.Validate = Expression.Lambda<Func<T, bool>>(body, parameter).Compile();
}
}
}
}
I am reading the "Head First Object Oriented Design and Analysis" and I am stuck on page 254.
In the java code below, I am trying to convert the "Matches" method to a c# one.
public class InstrumentSpec {
private Map properties;
public InstrumentSpec(Map properties) {
if (properties == null) {
this.properties = new HashMap();
} else {
this.properties = new HashMap(properties);
}
}
public Object getProperty(String propertyName) {
return properties.get(propertyName);
}
public Map getProperties() {
return properties;
}
public boolean matches(InstrumentSpec otherSpec) {
for (Iterator i = otherSpec.getProperties().keySet().iterator();
i.hasNext(); ) {
String propertyName = (String)i.next();
if (!properties.get(propertyName).equals(
otherSpec.getProperty(propertyName))) {
return false;
}
}
return true;
}
}
And this is the C# code that I have so far:
public class InstrumentSpec
{
private IDictionary _properties;
public InstrumentSpec(IDictionary properties)
{
this._properties = properties == null ? new Hashtable() : new Hashtable(properties);
}
public object GetProperty(string propertyName)
{
return _properties.Contains(propertyName);
}
public IDictionary Properties
{
get { return _properties; }
set { _properties = value; }
}
public virtual bool Matches(InstrumentSpec otherSpec)
{
foreach (var prop in otherSpec.Properties)
{
if (!prop.Equals(otherSpec.Properties))
{
return false;
}
}
return true;
}
}
Anyone has got any idea how to make the Matching method work so that it checks if two objects match?
The Java code iterates over the dictionary keys and compares the respective property values. You're currently iterating over the key/value pairs and compare them to the dictionary.
I guess something like
foreach (var key in otherSpec.Properties.Keys)
{
if (!Properties[key].Equals(otherSpec.Properties[key]))
{
return false;
}
}
return true;
would be a better translation.
Look at your comparison:
if (!prop.Equals(otherSpec.Properties))
When do you expect any single "property" to equal the collection of "properties" which contains it? The Java code is making comparisons with the object's internal collection of "properties":
if (!properties.get(propertyName).equals(
otherSpec.getProperty(propertyName)))
Which basically means it's looping through a collection of "properties" and for each "property" in that collection it is comparing it with a similarly named "property" in another collection. But you don't make any reference to the object's collection here:
private IDictionary _properties;
You need to compare the values from one collection to the values in the other collection. Without doing any checking if the values actually exist in the collection (which I recommend doing), it might look something like this:
foreach (var prop in otherSpec.Properties.Keys)
{
if (!otherSpec.Properties[prop].Equals(_properties[prop]))
{
return false;
}
}
return true;
You could completely copy the algorithm, if thats what you want:
public virtual bool Matches(InstrumentSpec otherSpec)
{
foreach (var prop in otherSpec.Properties.Keys)
{
if (!Object.equals(properties[prop], otherSpec[prop]))
{
return false;
}
}
return true;
}
But i would advise, to use generics, to know, which types we are talking about
Try this:
var keysEqual= Properties.Keys.SequenceEqual(otherSpec.Properties.Keys);
var valuesEqual = Properties.Values.SequenceEqual(otherSpec.Properties.Values);
if(keysEqual && valueEqual)
{
//objects have the same properties and values
}
Assume the following code:
public class CC3
{
private string _field;
private bool _someFlag;
public string Property
{
get { return _field; }
}
public bool SomeFlag
{
get { return _someFlag; }
}
public void SetField()
{
_field = " foo ";
_someFlag = true;
}
public string Method()
{
Contract.Requires(SomeFlag);
return Property.Trim();
}
}
The static checker of Code Contracts complains about the return statement of Method:
Possibly calling a method on a null reference 'this.Property'
What do I have to do to enable the static checker to prove that Property can never be null if SomeFlag is true?
You can give the static analysis a helping hand using Contract.Assume:
public string Method()
{
Contract.Requires(SomeFlag);
Contract.Assume(Property != null);
return Property.Trim();
}
Or actually add the check as a Contract.Requires in its own right. After all, just because you can manually prove it to be true for now, you can't guarantee that will always be the case when the code gets modified. In fact, consider whether SomeFlag being true is actually a requirement at all. Perhaps this is a cleaner solution:
public string Method()
{
Contract.Requires(Property != null);
return Property.Trim();
}
The only way to prove that it is not null is to prove that it is not null. Ideally you could use an invariant if you would convert to auto properties. For this example you could rewrite the property to ensure that null is not a possible result:
public string Property
{
get {
Contract.Ensures(Contract.Result<string>() != null);
return _field ?? String.Empty;
}
}
I have the following getter and setter method:
private Ansprechpartner partner;
public virtual Ansprechpartner Partner
{
get
{
if (partner == null)
{
// something like partner = " ";
}
return partner;
}
set
{
partner = value;
}
}
In the if clause i want to set partner = " ". But of course this isn't working, cause partner is a Typ a the class Ansprechpartner.
Is there a way to do something equivalent, so that partner returns an empty string if (partner == null)?
Please help
is Ansprechpartner your own class?
If it is, than you can return your own defenition of an "empty" Ansprechpartner
return Ansprechpartner.Empty;
and then define the empty property
public class Ansprechpartner
{
public static Ansprechpartner Empty
{
get
{
//generate an empty Ansprechpartner and return it here
}
}
You could override the ToString method from the Ansprechpartner and use a flag attribute like this:
public override ToString()
{
if (FlagAtrribute == null) //Or if it is a string, you could String.IsNullOrEmpty(FlagAtrribute)
{
return "";
}
return FlagAtrribute.ToString();
}
And in your getter just return a new empty instance of the Ansprechpartner class
get
{
if (partner == null)
{
partner = new Ansprechpartner();
}
return partner;
}
And in your code, do something like this:
MyClass.Partner.ToString();
If you change your return type from Ansprechpartner to object you can return anything you would like that derives from object. But I would strongly disagree with taking this approach. If you will want to rethink you're entire approach.
Your property doesn't actually appear to be working with strings, in which case returning a string would be an error.
However, answering your question directly of how to return a string, try something like this:
get
{
if (partner == null)
return String.Empty;
else
return partner;
}
}
Or, better yet:
get
{
return partner ?? String.Empty;
}
you could do something like:
get
{
if (partner == null)
return new Ansprechpartner() {whatever = ""};
else
return partner;
}
In my opinion there is a straightforward way to get exacly what you ask, that is to ensure that it is syntactically correct the folloging:
get
{
if (partner == null)
{
return = "";
}
return partner;
}
The way is to provide an implicict cast operator for the class. Thanks to implicit cast operator, the String.Empty or "" can be automatically casted to Ansprechpartner type, then it is perfectly legal the sysntax you use for the getter.
but what is a implicict cast operator ?
You can even see the question: How do I provide custom cast support for my class? for more detail.
I preferred, however, directly test the code for your class: the code used to successfully test it is the following:
private Ansprechpartner partner;
public virtual Ansprechpartner Partner
{
get
{
// legal assignment thanks to **public static implicit operator Ansprechpartner(string s)**
return partner ?? String.Empty;
}
set
{
partner = value;
}
}
We also try to make the inverse: thanks to public static implicit operator string(Ansprechpartner a) we see that is possible to assign an Empty string to a Ansprechpartner instance variabile
public void test_method()
{
Ansprechpartner s = String.Empty;
}
In the Ansprechpartner class we define cast operators
class Ansprechpartner
{
public static implicit operator Ansprechpartner(string s) {
// put your conversion logic here
// .. i.e: you can simply pass string s to a Ansprechpartner constructor
Ansprechpartner a = new Ansprechpartner();
return a;
}
public static implicit operator string(Ansprechpartner a)
{
if (a == null)
return "";
else
return a.ToString();
}
public Ansprechpartner()
{
}
public override string ToString()
{
return Value;
}
}
That's it, leave a comment if something has not been explained.
Good Morning All,
I'm trying to use "Contains" to see if an object is within the collection. When I break I can see that the object is indeed part of the collection however "Contains" seems to be returning false indicating the item is not in the collection. Any idea what I'm doing wrong?
if(HttpContext.Current.Session["AutoPayTypes"] != null)
{
var autopays = HttpContext.Current.Session["AutoPayTypes"] as List<PaymentTypeInfo>;
char? coverageProductLine = null;
if(entityProps.ContainsKey("CoverageProductLine"))
{
coverageProductLine = (char?)entityProps["CoverageProductLine"];
}
var paymentTypeInfoRepository = new PaymentTypeInfoRepository();
var payType = paymentTypeInfoRepository.GetPaymentTypeInfo(paymentAdd.PayType,
coverageProductLine);
if (autopays != null && payType != null)
paymentAdd.DaysPaid = autopays.Contains(payType) ? null : paymentAdd.DaysPaid;
}
If the object is not in the collection the "DaysPaid" needs to be null. Any ideas?
***UPDATE
PaymentTypeInfo is a standard LinqToSql generated class. Equals nor GetHashCode has been overridden at this point. Here is it's source.
[Table(Name="dbo.S_OptPaymentType")]
public partial class PaymentTypeInfo
{
private string _PaymentId;
private string _PaymentCode;
private System.Nullable<char> _CoverageType;
private string _ActionCode;
private System.Nullable<char> _PaymentType;
private string _BenAction;
private System.Nullable<char> _BenPremDisFlag;
private string _APNextToLastAct;
private string _APLastAct;
public PaymentTypeInfo()
{
}
[Column(Storage="_PaymentId", DbType="Char(3) NOT NULL", CanBeNull=false)]
public string PaymentId
{
get
{
return this._PaymentId;
}
set
{
if ((this._PaymentId != value))
{
this._PaymentId = value;
}
}
}
[Column(Storage="_PaymentCode", DbType="Char(2) NOT NULL", CanBeNull=false)]
public string PaymentCode
{
get
{
return this._PaymentCode;
}
set
{
if ((this._PaymentCode != value))
{
this._PaymentCode = value;
}
}
}
[Column(Storage="_CoverageType", DbType="Char(1)")]
public System.Nullable<char> CoverageType
{
get
{
return this._CoverageType;
}
set
{
if ((this._CoverageType != value))
{
this._CoverageType = value;
}
}
}
[Column(Storage="_ActionCode", DbType="VarChar(3)")]
public string ActionCode
{
get
{
return this._ActionCode;
}
set
{
if ((this._ActionCode != value))
{
this._ActionCode = value;
}
}
}
[Column(Name="PaymentType", Storage="_PaymentType", DbType="Char(1)")]
public System.Nullable<char> PaymentType
{
get
{
return this._PaymentType;
}
set
{
if ((this._PaymentType != value))
{
this._PaymentType = value;
}
}
}
[Column(Storage="_BenAction", DbType="VarChar(3)")]
public string BenAction
{
get
{
return this._BenAction;
}
set
{
if ((this._BenAction != value))
{
this._BenAction = value;
}
}
}
[Column(Storage="_BenPremDisFlag", DbType="Char(1)")]
public System.Nullable<char> BenPremDisFlag
{
get
{
return this._BenPremDisFlag;
}
set
{
if ((this._BenPremDisFlag != value))
{
this._BenPremDisFlag = value;
}
}
}
[Column(Storage="_APNextToLastAct", DbType="VarChar(3)")]
public string APNextToLastAct
{
get
{
return this._APNextToLastAct;
}
set
{
if ((this._APNextToLastAct != value))
{
this._APNextToLastAct = value;
}
}
}
[Column(Storage="_APLastAct", DbType="VarChar(3)")]
public string APLastAct
{
get
{
return this._APLastAct;
}
set
{
if ((this._APLastAct != value))
{
this._APLastAct = value;
}
}
}
}
Thanks,
~ck in San Diego
EDIT: As Ahmad pointed out, your conditional operator usage is incorrect. However, you don't even need to use the conditional operator here, as one of the branches results in a no-op. Just use this:
if (autopays != null && payType != null && !autopays.Contains(payType))
{
paymentAdd.DaysPaid = null;
}
Original answer
You haven't shown any thing about PaymentTypeInfo - does it override Equals and GetHashCode appropriately? If not, the containment check will be performed using reference identity, and it's very unlikely that the reference in the session is the same as the reference in the repository.
Either make PaymentTypeInfo override Equals and GetHashCode, or pass an appropriate IEqualityComparer<PaymentTypeInfo> into the Contains method.
(As SLaks mentions in the comments, in this case GetHashCode won't actually get called - but you should always override both Equals and GetHashCode or neither of them; if you do override them, you should do so in a consistent manner.)
Unless payType overrides Equals or you specify an IEqualityComparer, Contains will compare by reference.
Your collection probably contains a different instance of the class which is logically equivalent.
It's possible you're running into an equality issue - Contains() uses the IEquatable.Equals method, so you might check to make sure that that's going to return true for separate instances of the PaymentTypeInfo class.
Every post so far has a valid point; depending on the type being used Contains may not suffice. I am addressing a different part of your question though:
If the object is not in the collection
the "DaysPaid" needs to be null. Any
ideas?
How about switching the order of your ternary operator values to match the above statement? Use this:
paymentAdd.DaysPaid = autopays.Contains(payType) ? paymentAdd.DaysPaid : null;
Instead of this:
paymentAdd.DaysPaid = autopays.Contains(payType) ? null : paymentAdd.DaysPaid;
If the statement evaluates to false the 2nd item will be used, so make it null. The structure is:
logic statement ? true : false
Can you post the source of the PaymentType class? I am fairly certain that this type does not provided value-based semantics so the Contains method is forced to resort to using identity equality (which is not giving you the results you want).
If this is the case you may be interested in these articles I wrote on this topic:
All types are not compared equally
All types are not compared equally (part 2)