Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Monday, September 22, 2008 2:51 PM
Hi, when I call the property "IsDefault" on an object inheriting from SettingsBase, I get an error because "this.GetType() in line 5 below returns null. Why does GetType() return null, and how do I get around this?
Thanks in advance, Ben
public abstract class SettingsBase
{
public SettingsBase GetDefault()
{
return (SettingsBase)this.GetType().GetProperty("Default").GetGetMethod().Invoke(this, null);
}
public bool IsDefault
{
get
{
return this.Equals(GetDefault());
}
}
}
public abstract class SettingsBase<tself> : SettingsBase
where TSelf : SettingsBase<tself>
{
public static TSelf Default
{
get
{
TSelf result = CreateInstance();
result.LoadDefaultValues();
return result;
}
}
private static TSelf CreateInstance()
{
return (TSelf)typeof(TSelf).GetConstructor(Type.EmptyTypes).Invoke(null);
}
protected abstract void LoadDefaultValues();
public override bool Equals(object obj)
{
return Equals(obj as TSelf);
}
public abstract bool Equals(TSelf other);
}</tself></tself>
All replies (8)
Tuesday, September 23, 2008 2:56 AM âś…Answered
Why does GetProperty("Default") return null?
Because Default is a static property of a base class of the Type that you're calling GetProperty() on. Static methods are not inherited, although they are accessible from derived classes. But from the reflection point of view, Default is a property of a different type up the hierarchy.
You can get around this by doing:
PropertyInfo pi = t.GetProperty("Default", BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public);
However, if you can get it done without reflection, do use that method. I have not analyzed the intentions of the code, but I have a feeling there's a much simpler way of achieving what you want. No time for that now though. The above was because the problem as such is valid, and the solution non-obvious.
Monday, September 22, 2008 3:03 PM
it looks like the code editor cut off the generic type in the declaration of the second class. it should be: public abstract class SettingsBase"TSelf" where I put quotes instead of the brackets so they don't get deleted again.
Monday, September 22, 2008 3:41 PM
Is this an entry into an obfuscation contest... [:S] ? What are you trying to do?
this.GetType()
Are you really sure this is what happens? That GetType() returns null? How about breaking apart that one-liner, and store the intermediate results in variables and check just where it goes wrong? (You can always put it back together before sending in your final entry in the contest...;-)
If you could provide a complete compileable sample it'd be easier to analyze...
Monday, September 22, 2008 3:57 PM
haha, no, am not competing :)
I have found a way to get what I want without using reflection, and both ways are shown.
You're right (as usual) it was not GetType() but GetProperty("Default") that was returning null. Why does GetProperty("Default") return null? "Default" is a static property, by the way.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
Settings s = Settings.Default;
MessageBox.Show(s.IsDefault.ToString());
base.OnLoad(e);
}
}
public abstract class SettingsBase
{
// This function creates a null exception
public SettingsBase GetDefaultUsingReflection()
{
Type t = this.GetType();
PropertyInfo pi = t.GetProperty("Default"); // returns null
return (SettingsBase)pi.GetGetMethod().Invoke(this, null);
}
// I found a way to achieve required functionality without reflection.
public abstract SettingsBase GetDefault();
public bool IsDefault
{
get
{
return this.Equals(GetDefault());
//this way will throw error
// return this.Equals(GetDefaultUsingReflection());
}
}
}
public abstract class SettingsBase<TSelf> : SettingsBase, IEquatable<tself>
where TSelf : SettingsBase<tself>
{
public override SettingsBase GetDefault()
{
return Default;
}
public static TSelf Default
{
get
{
TSelf result = CreateInstance();
result.LoadDefaultValues();
return result;
}
}
static TSelf CreateInstance()
{
return (TSelf)typeof(TSelf).GetConstructor(Type.EmptyTypes).Invoke(null);
}
protected abstract void LoadDefaultValues();
public abstract string GetUniqueDescription();
public override bool Equals(object obj)
{
return Equals(obj as TSelf);
}
public abstract bool Equals(TSelf other);
public virtual string GetStrategyName()
{
return this.GetType().DeclaringType.Name;
}
}
public class Settings : SettingsBase<Settings>
{
public double MinStockPrice { get; set; }
public int MinStockVolume { get; set; }
public int MinDaysUntilEarnings { get; set; }
public int MinDaysSinceEarnings { get; set; }
public double MaxIV { get; set; }
public int MinOpenInterest { get; set; }
public int MinDaysToExpiry { get; set; }
public int MaxDaysToExpiry { get; set; }
public int[] CrossOvers { get; set; }
public int[] CrossUnders { get; set; }
public PriceActionFilter Filter;
public struct PriceActionFilter
{
public enum CrossFilter
{
None,
CrossedOver,
CrossedUnder
}
public enum LevelFilter
{
None,
MadeNewHigh,
MadeNewLow,
DidNotMakeNewHigh,
DidNotMakeNewLow
}
public CrossFilter CrossFilterValue;
public LevelFilter LevelFilterValue;
public PriceActionFilter(CrossFilter crossFilter, LevelFilter levelFilter)
{
CrossFilterValue = crossFilter;
LevelFilterValue = levelFilter;
}
public override string ToString()
{
return ToXML();
}
public string ToXML()
{
StringWriter sw = new StringWriter();
XmlSerializer xs = new XmlSerializer(typeof(PriceActionFilter));
xs.Serialize(sw, this);
return sw.ToString();
}
public static PriceActionFilter FromXML(string xml)
{
StringReader sr = new StringReader(xml);
XmlSerializer xs = new XmlSerializer(typeof(PriceActionFilter));
return (PriceActionFilter)xs.Deserialize(sr);
}
public override bool Equals(object obj)
{
if (!(obj is PriceActionFilter))
return false;
return Equals((PriceActionFilter)obj);
}
public bool Equals(PriceActionFilter other)
{
return ((this.CrossFilterValue == other.CrossFilterValue)
&& (this.LevelFilterValue == other.LevelFilterValue));
}
}
public override string ToString()
{
return ToXML();
}
public string ToXML()
{
StringWriter sw = new StringWriter();
XmlSerializer xs = new XmlSerializer(typeof(Settings));
xs.Serialize(sw, this);
return sw.ToString();
}
public static Settings FromXML(string xml)
{
StringReader sr = new StringReader(xml);
XmlSerializer xs = new XmlSerializer(typeof(Settings));
return (Settings)xs.Deserialize(sr);
}
public override string GetUniqueDescription()
{
return ToXML();
}
internal Settings Clone()
{
return (Settings)this.MemberwiseClone();
}
protected override void LoadDefaultValues()
{
MinStockPrice = 15;
MinStockVolume = 500000;
MinDaysUntilEarnings = 5;
MinDaysSinceEarnings = 1;
MaxIV = 0.75;
MinOpenInterest = 50;
MinDaysToExpiry = 15;
MaxDaysToExpiry = 90;
CrossOvers = new int[] { 22, 50, 200 };
CrossUnders = new int[] { 22, 50, 200 };
Filter = new PriceActionFilter(PriceActionFilter.CrossFilter.None, PriceActionFilter.LevelFilter.None);
}
public override bool Equals(Settings other)
{
if (null == other)
return false;
return ((this.MinStockPrice == other.MinStockPrice)
&& (this.MinStockVolume == other.MinStockVolume)
&& (this.MinDaysUntilEarnings == other.MinDaysUntilEarnings)
&& (this.MinDaysSinceEarnings == other.MinDaysSinceEarnings)
&& (this.MaxIV == other.MaxIV)
&& (this.MinOpenInterest == other.MinOpenInterest)
&& (this.MinDaysToExpiry == other.MinDaysToExpiry)
&& (this.MaxDaysToExpiry == other.MaxDaysToExpiry)
&& (ArraysEqual(this.CrossOvers, other.CrossOvers))
&& (ArraysEqual(this.CrossUnders, other.CrossUnders))
&& (this.Filter.Equals(other.Filter)));
}
protected bool ArraysEqual(int[] l1, int[] l2)
{
if (null == l1)
return (null == l2);
if (null == l2)
return false;
if (l1.Length != l2.Length)
return false;
Array.Sort(l1);
Array.Sort(l2);
for (int i = 0; i < l1.Length; i++)
if (l1[i] != l2[i])
return false;
return true;
}
}
}</tself></tself>
Monday, September 22, 2008 3:58 PM
so sorry about the code formatting ... guess you can paste it into visual studio if you're curious enough. thanks
Monday, September 22, 2008 4:58 PM
so sorry about the code formatting ...
You can paste code that looks nice by using the "Source Code" button in the toolbar (it has two green curly braces)
Monday, September 22, 2008 5:10 PM
ok done.
Tuesday, September 23, 2008 11:30 AM
Many thanks