|
|
Comments and Discussions
|
|
 |

|
Hi, I've read very good things about this on the intertubes, but I'm having trouble groking how to use this. I've converted HyperDescriptor to .NET 4 via a comment on StackOverflow.
I use the following method to assign dictionary values to an objects properties where the dictionary keys match properties in the DTO.
It seems that this would be simple and ripe for HyperDescriptor, but I'm having trouble implementing.
(I'm leaving out some implementation not relevant for discussion because it would confuse the matter, let's just say I need Reflection to accomplish what I need. Hence, HD.)
private void BuildClassDTOFromDictionary( Dictionary userData )
{
ClassDTO classDTO = new ClassDTO();
Type type = typeof( ClassDTO );
System.Reflection.PropertyInfo[] properties = type.GetProperties();
foreach( string key in userData.Keys )
{
string value = userData.Get( key );
foreach( System.Reflection.PropertyInfo propertyInfo in properties )
{
string name = propertyInfo.Name;
if( name.Equals( key, StringComparison.OrdinalIgnoreCase ) == true )
{
try
{
propertyInfo.SetValue( classDTO, value, null );
}
catch( Exception )
{
}
break;
}
}
}
}
Thanks much.
|
|
|
|

|
Hi Mark,
Used your code as VB.NET but it looks like the GetProperties is not working.
Dim props As PropertyDescriptorCollection = Nothing
props = TypeDescriptor.GetProperties(A)
This statement returns NULL.
I also want to know if Code can be integrated with the Dynimic Demo (SilverLight) example.
Here is the snippet of the code in which I want to integrate above code so that below code works faster.
Namespace DynamicSilverLightVB
Public Class DynamicDemo
#Region "var's"
Private extendedType As Type = Nothing
#End Region
#Region "CreatePresentable"
Public Function CreatePresentable(ByVal src As Object, ByVal extendedPropertiesDict As Dictionary(Of String, Type)) As PresentingData
'create the Object type & class based on the dictionary - hold the extended class in a variable of the base-type
Dim classicEx As PresentingData = DynamicFactory.CreateClass(Of PresentingData)(GetExtendedType(Of PresentingData)(extendedPropertiesDict))
'fill in the base-type's properties
classicEx.Composer = src.ComposerName
classicEx.Composition = src.CompositionName
classicEx.Orquestra = src.Orquestra
classicEx.Conductor = src.Conductor
'fill in the dynamically created properties
SetExtendedProperties(TryCast(classicEx, Object), src, extendedPropertiesDict)
Return classicEx
End Function
#End Region
#Region "GetExtendedType"
'generic method that will extend dynamically the type T. keeping a global variable that holds the Object type
'makes sure I create type only once (the class on the other hand has to be instantiated for each data-row
Protected Function GetExtendedType(Of T As Class)(ByVal extendedPropertiesDict As Dictionary(Of String, Type)) As Type
If extendedType Is Nothing Then
extendedType = DynamicFactory.ExtendTheType(Of T)(extendedPropertiesDict)
End If
Return extendedType
End Function
#End Region
#Region "SetExtendedProperties"
'generic method that enumerates the dictionary and populate the Object class with values from the source
'class that contains all the 20 columns.
'there is an assumption here that the newly created properties have the same name as the original ones
'in the source class.
'the Object class (destination) is passed-in using the keyword Object in order defer the GetType()
'operation until runtime when the Object type is available.
Public Sub SetExtendedProperties(Of T)(ByVal dest As Object, ByVal src As T, ByVal extendedPropsDict As Dictionary(Of String, Type))
For Each word As Object In extendedPropsDict
Dim src_pi = src.[GetType]().GetProperty(word.Key)
Dim dest_pi = TryCast(dest.[GetType]().GetProperty(word.Key), PropertyInfo)
Dim val = src_pi.GetValue(src, Nothing)
'format the data based on its type
If TypeOf val Is DateTime Then
dest_pi.SetValue(dest, DirectCast(val, DateTime).ToShortDateString(), Nothing)
ElseIf TypeOf val Is Decimal Then
dest_pi.SetValue(dest, CDec(val).ToString("C"), Nothing)
Else
dest_pi.SetValue(dest, val, Nothing)
End If
Next
End Sub
#End Region
End Class
|
|
|
|

|
Great tool but...
Not working with virtual properties
Best regards
|
|
|
|

|
One tiny improvement would be to check the properties dictionary right after the call to descriptor.SupportsChangeEvents.
If you only mark up the base class, on the first inherited property in the child the SupportsChangeEvents call loops in to build the properties of the base class and this has the consequence of filling in the properties dictionary, so by the time we come back to the child, the property we're building has already been added and properties.Add(property, descriptor) ends up throwing an exception, which (I believe) subsequently prevents this one property from using the hyper descriptor in the child.
Something like the below would avoid this scenario.
bool supportsChangeEvents = descriptor.SupportsChangeEvents, isReadOnly = descriptor.IsReadOnly;
if (properties.TryGetValue(property, out foundBuiltAlready))
{
descriptor = foundBuiltAlready;
return true;
}
|
|
|
|
|

|
can you please advise how to correctly call default implementation?
|
|
|
|

|
actually the default implementation returns null too. (string Name = TypeDescriptor.GetFullComponentName(new Collection<string>());
so all I need is just to use TypeDescriptor.GetClassName(Component) instead. It returns fully qualified class name.
|
|
|
|

|
Hi,
I'm getting a stackoverflow exception when I add two types where one type inherits from another. See the nunit test below. I'm using .Net 3.5, am I using the code incorrectly as I'm sure a bug like this would have been picked up by now?
Damien
public class Entity
{
public string Name { get; set; }
}
public class EntityEx :Entity
{
public string FullName { get; set; }
}
[TestFixture]
public class HyperPropertyDescriptorTests
{
[Test]
public void Stackoverflow()
{
HyperTypeDescriptionProvider.Add(typeof(EntityEx));
HyperTypeDescriptionProvider.Add(typeof(Entity));
var Properties = TypeDescriptor.GetProperties(typeof(EntityEx));
Properties = TypeDescriptor.GetProperties(typeof(Entity)); }
}
|
|
|
|

|
OK; I'll have a look - I've got some other changes to do too.
|
|
|
|

|
I'm still investigating the stack overflow, but note that a simple fix is... don't do that It works fine (including sub-types) if you set at the base only:
HyperTypeDescriptionProvider.Add(typeof(Entity));
|
|
|
|

|
Unfortunately not possible in my case as I lazy load and cache PropertyInfo objects of a type when needed so the order that they would be added to HyperDescriptor is unknown and can change depending on usage.
The unit test was only an example to prove the exception.
I ended up using an Expression.Lambda instead to get a bit of performance gain, would still like to test HyperPropertyDescriptor though.
Damien
|
|
|
|

|
I am getting same error. Any solution for this???
|
|
|
|

|
I just posted a fix, see below
|
|
|
|

|
I also had this problem, and needed to find a solution since I was using it in a generic library where I couldn't make any assumptions about the structure or relations of the types I was adding to the Hyper providers.
After grappling with this problem for a couple days with a massive headache, I finally found a solution to this. I added the following code in GetTypeDescriptor() just before SyncLock descriptors:
If descriptors.ContainsKey(objectType.BaseType) Then
Return MyBase.GetTypeDescriptor(objectType, instance)
End If
I'm still not 100% sure what impact this has, and it may mean that sub-types don't see the performance benefits, but that is far better than not working at all.
Edit: See reply for better solution!
modified 5-Mar-13 18:19pm.
|
|
|
|

|
I created a series of tests that tries all the different combinations and orders of adding a base type and sub-type to the HyperTypeDescriptionProvider and getting the PropertyDescriptors for those types, to nail down the exact circumstances that will cause the stack overflow. I found two situations that resulted in the error:
- Add base type to hyper
- Get base type descriptors
- Add sub-type to hyper
- Get sub type descriptors <-- causes stack overflow
And:
- Add sub-type to hyper
- Add base type to hyper
- Get sub type descriptors <-- causes stack overflow
I also created a series of tests that measures the time to access properties before and after adding/removing types from Hyper, also using different combinations and orders of a base and sub-type, to ensure that no matter what order you add types in, you will see the performance benefit.
Another problem that I found was that removing or clearing a type from HyperTypeDescriptionProvider did not actually remove the type from TypeDescriptor. Not only that, but it could cause the stack overflow if you removed a type and re-added it.
I was determined to fix the stack overflow, the type removal, and get all of my tests to pass. I am proud to announce that I was successful!! I cannot get it to cause a stack overflow, and the performance benefit is seen no matter what order you add types.
Here is my version of HyperTypeDescriptionProvider (.NET 4.0... to compile this in earlier versions, replace occurrences of 'var' with their respective types and replace the attributes on BuildDescriptor with the ones in the original post):
public sealed class HyperTypeDescriptionProvider : TypeDescriptionProvider
{
private static readonly Dictionary<Type, ICustomTypeDescriptor> descriptors = new Dictionary<Type, ICustomTypeDescriptor>();
private static readonly Dictionary<Type, TypeDescriptionProvider> providers = new Dictionary<Type, TypeDescriptionProvider>();
public static void Add(Type type)
{
lock (descriptors)
{
if (!providers.ContainsKey(type))
{
var baseFound = false;
if (type.BaseType != null && providers.ContainsKey(type.BaseType))
{
baseFound = true;
Remove(type.BaseType);
}
var provider = new HyperTypeDescriptionProvider(TypeDescriptor.GetProvider(type));
TypeDescriptor.AddProvider(provider, type);
providers.Add(type, provider);
provider.GetTypeDescriptor(type);
if (baseFound)
Add(type.BaseType);
}
}
}
public static void Remove(Type type)
{
lock (descriptors)
{
TypeDescriptor.RemoveProvider(providers[type], type);
providers.Remove(type);
descriptors.Remove(type);
}
}
public static void Clear()
{
lock (descriptors)
{
foreach (var provider in providers)
TypeDescriptor.RemoveProvider(provider.Value, provider.Key);
providers.Clear();
descriptors.Clear();
}
}
private HyperTypeDescriptionProvider()
: this(typeof(object))
{ }
private HyperTypeDescriptionProvider(Type type)
: this(TypeDescriptor.GetProvider(type))
{ }
private HyperTypeDescriptionProvider(TypeDescriptionProvider parent)
: base(parent)
{ }
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
lock (descriptors) {
ICustomTypeDescriptor descriptor;
if (!descriptors.TryGetValue(objectType, out descriptor)) {
try
{
descriptor = BuildDescriptor(objectType);
}
catch
{
return base.GetTypeDescriptor(objectType, instance);
}
}
return descriptor;
}
}
[SecuritySafeCritical]
[ReflectionPermission(SecurityAction.Assert, Unrestricted = true)]
private ICustomTypeDescriptor BuildDescriptor(Type objectType)
{
var descriptor = base.GetTypeDescriptor(objectType, null);
descriptors.Add(objectType, descriptor);
try
{
descriptor = new HyperTypeDescriptor(descriptor);
descriptors[objectType] = descriptor;
return descriptor;
}
catch
{ descriptors.Remove(objectType);
throw;
}
}
}
Note that I call GetTypeDescriptor() in Add(). Normally, this wouldn't be necessary, as it is set up to do a sort of lazy building of descriptors, but this was the only way I found to prevent a stack overflow in the second error situation I mentioned. I also renamed the Clear(Type) method to Remove(Type) so that it is consistent with .NET naming conventions.
modified 6-Mar-13 9:37am.
|
|
|
|

|
Awesome stuff...
Firstly, thanks to Marc Gravell, and then to you, mattstermiller, for fixing the stack overflow...
|
|
|
|

|
First of all: thank you! Superb!
One question: how to get it working with internal classes if possible?
In the sample application changing the test class declaration to internal (internal class MySuperEntity : MyEntity {...}) causes the exception:
Unhandled Exception: System.Reflection.TargetInvocationException: Property accessor 'When' on object 'HyperPropertyDescriptorSample.MySuperEntity' threw the following exception:'HyperPropertyDescriptorSample.MySuperEntity.get_When()' ---> System.MethodAccessException: HyperPropertyDescriptorSample.MySuperEntity.get_When() ---> System.Security.SecurityException: Request failed.
However even if no way to go with internals i'll just change my DTOs to public...
|
|
|
|

|
That should be pretty simple to fix, perhaps using `DynamicMethod` with the associated type. I'll take a look after xmas (otherwise I'm going to need surgical help to extract my laptop).
|
|
|
|

|
Dear Marc,
I am working on a .net add-in which requires access to the sealed class(.Net Base Class Microsoft.VisualBasic.Collection), I want to access key and value.
I could not find any help regarding this though u can see .net quick watch can access its value and as per my knowledge it does through reflection.
Can you provide me some help for two problems.
1) how to access nested internal class members.
2) how to access sealed class members.
(I know that if sealed class is derived from a base class then through virtual function inherited from base class you can access sealed class members but as in .net base class is object and its already sealed)
If possible provide me any code example.
Thanks in advance.
|
|
|
|

|
Hi,
First thank you very much for this article.
We found just something that looks like a bug.
We have a list of classes X1, ... Xn using the HyperProp.
We have a control bound to the list typeof(X1),... typeof(Xn)
The binding ask the property descriptor of typeof(X1) that is a "System.RuntimeType".
Your class than try to call the BuildDescriptor also for "System.RuntimeType".
Finally the HP will do it foreach "System.RuntimeType" associated to each typeof(X1), ... typeof(Xn).
This doesn't work, unless we add the following line:
if (objectType.FullName.Equals("System.RuntimeType"))
return base.GetTypeDescriptor(objectType, instance);
at the beginning of
public sealed override ICustomTypeDescriptor GetTypeDescriptor(...)
i.e. we don't use the HP for the System.RuntimeType associated to the type X1; but we continue to use HP for the type X1.
Now it works also for this special case, but I would like to hear your opinion.
Thank you.
Claudio
|
|
|
|

|
Hello, Marc Gravell, I have been searching for some code to speed up the performance of sorting generic collection based on dynamic property access. Acoring to the measurements you have done, it could be what I am looking for.
I have a simple code that creates 50,000 objects of CustomClass and adds them to a CustomBindingList<T> (inherits from BindingList<T>). In the ApplySortCore I call sort method and pass it a CustomPropertyComparer. All works well, but the problem is performance. For sorting 50,000 objects it needs 10 seconds, while when DataGridView bound to DataTable it needs less than a second (more like a 10th of second).
Is your method applicable for sorting? Before I go deep into the understanding how it works, I would like to know if it is good for what I want to achieve. When I set TypeDescriptorProvider to HyperTypeDescriptionProvider of my CustomClass, when it is about to display records it throws a series of exceptions which I catch in DataGridView DataError event:
{"WindowsFormsApplication1.Article.get_ID()"}
[System.MethodAccessException]: {"WindowsFormsApplication1.Article.get_ID()"}
Data: {System.Collections.ListDictionaryInternal}
HelpLink: null
InnerException: null
Message: "WindowsFormsApplication1.Article.get_ID()"
Source: "Hyper.ComponentModel.dynamic"
StackTrace: " at _c1.GetValue(Object )\r\n at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetValue(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)"
TargetSite: {System.Object GetValue(System.Object)}
Thanks in advance,
Goran
|
|
|
|

|
Given the numbers you quote, I wonder if you simply haven't disabled notifications during the sort?
HyperDescriptor certainly could be used that way; I've done a number of sortable binding list implementations, for example (also shows disabling notifications):
http://groups.google.co.uk/group/microsoft.public.dotnet.languages.csharp/msg/2b7528c689f9ef84
Since it uses PropertyDescriptor etc, it should be fully compatible with HyperDescriptor.
Marc
|
|
|
|

|
Hello, Marc, I thank you for the response. Disabling notifications didnt make much difference, the result are very similar. I just copied whole code you have provided, created an AdvancedList<Article> and binded it to DatagridView. Article is a simple class with three properties.
When I tied applying HyperTypeDescriptionProvider with AdvancedList, it doesn't throw any exception anymore, it does fill all 50,000 rows with 3 columns, but all cells have null value, so I was unable to test it in combination with HyperTypeDescriptionProvider.
For the illustration purposes, when using List<article),>
list.Sort(delegate (Article a1, Article a2){return a1.ID.CompareTo(a2.ID);}); // property name hardcoded
needs 0.04 seconds. Is there nothing to do to improve performance?
|
|
|
|

|
I would have to have a look; I can't do right now, but should be able to have a look by Monday. For completeness, which framework are you using: 2.0, 3.0, 3.5?
Marc
|
|
|
|

|
Marc, I cant thank you enough. I am extensively using framework 2.0, but testing and measurements have been done in 3.5.
I will also investigate during the weekend, but I cant say I am versed at it the way you are, judging by the code you write.
Thanks again,
Goran
|
|
|
|

|
It sounds like I should limit myself to 2.0 features, then.
I will have a look and post back.
|
|
|
|

|
Thanks. Btw, wen you do some testing and think there are some stuff that exist in 3.5 that could help in speeding things up, then I would be grateful if you could just drop some pointer(s) to a class/interface to research, and I will bookmark it for the future reference.
|
|
|
|

|
Here we go; results first: First run is for JIT SortableBindingList<T>: 7ms, 20 items List<T>: 0ms, 20 items Main run without HyperDescriptor SortableBindingList<T>: 2433ms, 50000 items List<T>: 47ms, 50000 items Enabling HyperDescriptor... First run is for JIT SortableBindingList<T>: 0ms, 20 items List<T>: 0ms, 20 items Main run with HyperDescriptor SortableBindingList<T>: 157ms, 50000 items List<T>: 55ms, 50000 items So a *definite* improvement - about 15 times quicker using the Hyper code... Here's the full sample: using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using Hyper.ComponentModel; public class SomeType { public int Number { get; set; } public string Name { get; set; } public double Value { get; set; } public override string ToString() {return Name; } } static class Program { static string GetString(Random rand) { const string fromSet = " abcdefghijklmnopqrstuvwxzy ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789"; char[] chars = new char[rand.Next(5, 20)]; for (int i = 0; i < chars.Length; i++) { chars[i] = fromSet[rand.Next(0, fromSet.Length)]; } return new string(chars); } static void Main() { Console.WriteLine("First run is for JIT"); RunTest(20); Console.WriteLine("Main run without HyperDescriptor"); RunTest(50000); Console.WriteLine("Enabling HyperDescriptor..."); HyperTypeDescriptionProvider.Add(typeof(SomeType)); Console.WriteLine("First run is for JIT"); RunTest(20); Console.WriteLine("Main run with HyperDescriptor"); RunTest(50000); } static void RunTest(int size) { Random rand = new Random(123456); SortableBindingList<SomeType> list = new SortableBindingList<SomeType>(); for (int i = 0; i < size; i++) { SomeType obj = new SomeType(); obj.Number = rand.Next(0, 1000); obj.Value = rand.NextDouble(); obj.Name = GetString(rand); list.Add(obj); } List<SomeType> vanilla = new List<SomeType>(list); IBindingList bindingList = list; PropertyDescriptor prop = TypeDescriptor.GetProperties(typeof(SomeType))["Value"]; Stopwatch timer = Stopwatch.StartNew(); bindingList.ApplySort(prop, ListSortDirection.Ascending); timer.Stop(); Console.WriteLine("SortableBindingList<T>: {0}ms, {1} items", timer.ElapsedMilliseconds, size); timer = Stopwatch.StartNew(); vanilla.Sort((x, y) => x.Value.CompareTo(y.Value)); timer.Stop(); Console.WriteLine("List<T>: {0}ms, {1} items", timer.ElapsedMilliseconds, size); } } class SortableBindingList<T> : BindingList<T> { internal abstract class SortProxy : IComparer<T> { public static SortProxy Create(bool isAscending, PropertyDescriptor property) { if (property == null) throw new ArgumentNullException("property"); return (SortProxy) Activator.CreateInstance( typeof(SortProxy<>).MakeGenericType(typeof(T), property.PropertyType), isAscending, property); } private readonly bool isAscending; private readonly PropertyDescriptor property; public bool IsAscending { get { return isAscending; } } public PropertyDescriptor Property { get { return property; } } protected SortProxy(bool isAscending, PropertyDescriptor property) { this.isAscending = isAscending; this.property = property; } public abstract int Compare(T x, T y); } internal sealed class SortProxy<TValue> : SortProxy { public SortProxy(bool isAscending, PropertyDescriptor property) : base(isAscending, property) { this.comparer = Comparer<TValue>.Default; } private readonly Comparer<TValue> comparer; public override int Compare(T x, T y) { TValue xVal = (TValue)Property.GetValue(x), yVal = (TValue)Property.GetValue(y); int result = comparer.Compare(xVal, yVal); return IsAscending ? result : -result; } } SortProxy sortProxy; protected override bool IsSortedCore { get { return sortProxy != null;} } protected override void RemoveSortCore() { sortProxy = null; } protected override ListSortDirection SortDirectionCore { get { return sortProxy == null || sortProxy.IsAscending ? ListSortDirection.Ascending : ListSortDirection.Descending; } } protected override PropertyDescriptor SortPropertyCore { get { return sortProxy == null ? null : sortProxy.Property; } } protected override bool SupportsSortingCore { get {return true;} } protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { sortProxy = SortProxy.Create(direction == ListSortDirection.Ascending, prop); bool oldNotify = RaiseListChangedEvents; try { RaiseListChangedEvents = false; List<T> list = new List<T>(this); list.Sort(sortProxy); this.ClearItems(); foreach (T item in list) this.Add(item); } finally { RaiseListChangedEvents = oldNotify; } ResetBindings(); } }
|
|
|
|

|
Hi Marc, what can I say.... great performance improvement. The trick to pass a property value type to comparer really speeded things up (in addition to HyperTypeDescriptionProvider). Never seen an approach to handle this by creating an abstract base class comparer to serve as a "bridge" for switching type T.
I did change one bit of code, which also gave some improvements (aprox 3%)
changed
RaiseListChangedEvents = false;
List<t> list = new List<t>(this);
list.Sort(sortProxy);
this.ClearItems();
foreach (T item in list) this.Add(item);
to
RaiseListChangedEvents = false;
List<t> list = this.Items as List<t>;
list.Sort(sortProxy);
Another thing, regarding the empty cells I have been getting while binding datagridview to list - the issue arrised if CustomType is not public. In order to work, SomeType must be declared as public - why is that?
Now I am up to studying the code for HyperTypeDescriptionProvider. I like to know and understand what I am using. Once again, thanks for the effort and great code. Much appreciated.
Goran
modified on Sunday, October 19, 2008 9:05 AM
|
|
|
|

|
Re 3.5, Expression... however, building a dynamic expression and compiling to a delegate (a Comparison in this case) is not trivial... However, IIRC there is (or will be soon) a "projection comparer" in the MiscUtil library I worked on with Jon Skeet.
http://www.pobox.com/~skeet/csharp/miscutil/
|
|
|
|

|
Hello Marc,
Is there a VB version of your work?
Thank you!
Marc R.
|
|
|
|

|
No, but you should be able to compile the dll using either C# Express, or MSBuild (at the command line) if you don't already have a C# IDE installed. You could then reference the dll from your VB project.
Would that do?
|
|
|
|

|
I was considering a change to my design, for potential performance reasons, until I discovered this article.
The increase in performance was dramatic (though my timings are not scientific).
For extreme testing I created a datatable of 100,000 rows with 50 string columns. 100,000 business objects were created, from the datatable.
The business object properties were mapped to the table columns via System.Attribute.
Original time ~ 50 seconds (using PropertyInfo Setvalue)
Using your hyperdescriptor method ~ 4 seconds
Cheers,
Tony Evans (A former colleague)
PS. Regards to all in the office
|
|
|
|

|
Hi again Tony - it has been a while!
Glad the code was useful - one of the "fun" (wrong word, perhaps) things I do on the train
Hope all is well,
Marc
|
|
|
|

|
Hi,
First of all: Great job!
But I run into a small problem, when I add my object to HyperTypeDescriptionProvider GetFields is not working anymore, it returns an empty array. I think enums are not handled correctly.
public enum UserType {guest, user, powerUser }
PropertyDescriptor propDest = propDest["UserType"];
Type tp = propDest.GetType();
FieldInfo[] fields = tp.GetFields(); // <--- here I get an empty array.
Do you know how this can be fixed?
Thanks,
Romy
|
|
|
|

|
You've called GetType() on the PropertyDescriptor; this gives you the type of the specific PropertyDescriptor implementation, which is nothing to do with the enum. What fields are you after? The static enum fields [the enums themselves]? Or the fields of the type that has the enum as a property?
|
|
|
|

|
it works... my mistake.
instead of calling propDest.PropertyType; I used propDest.GetType();
Thanks
Romy
|
|
|
|

|
Glad 'tis sorted. Any other queries, let me know.
Marc
|
|
|
|

|
but you know that
|
|
|
|

|
Cheers. Hope it helps
|
|
|
|

|
Very nice article. It's an interesting topic you tackled, and I enjoyed reading it.
I was thinking that you might consider having the class use a "fallback" plan, when running without ReflectionPermission available. Having the fallback logic in your class would allow all users of the class to not have to worry about the permissions aspect. Here[^] is a good write-up about this topic.
:josh:
My WPF Blog[ ^]
Enjoy! Vote! Learn! Love! Save the whales! Eat raw diamonds! Do the Foxtrot in your tighty-whiteys! Start fires! Kill Martians!
|
|
|
|

|
Interesting thought - I will investigate, but the fallback is already there: without this permission I would expect an exception to be thrown (when trying to usee reflection), which will already be caught and handled by simply not creating a bespoke descriptor - see the "catch" in TryCreatePropertyDescriptor. Since the PropertyDescriptorCollection is cached, this will only be attempted once, though, so maybe worth not even trying to create (or cache) until we have the permission.
|
|
|
|

|
The fallback is sort of there. The problem is, if you actually don't have permission to use reflection, the HyperPropertyDescriptor blows up when you access it.
There are several problems, but the most immediate is the fact that you are doing reflection work in its static ctor. Also, if you don't have reflection permission, the JIT compiler will throw an exception if a method is executed which happens to contain reflection code (the same applies for all permissions in the CAS model in general).
To work around this frustrating aspect of the CLR, you will want to use the following pattern, to keep the CLR happy:
void Foo()
{
ReflectionPermission perm =
new ReflectionPermission( ReflectionPermissionFlag.AllFlags );
try
{
perm.Assert();
FooWithPermission();
}
catch
{
}
}
void FooWithPermission()
{
}
If you want to test what it's like to use your code in an environment which does not allow reflection (which is the default for running off a network drive, or an exe from the internet), then you can do the following:
new ReflectionPermission( ReflectionPermissionFlag.AllFlags ).Deny();
Put that line of code at the top of Main().
I'm no expert on .NET security programming, so don't take my word for it. There might be better ways to skin this cat, but I've used the techniques presented above...so I know they work!
:josh:
My WPF Blog[ ^]
Enjoy! Vote! Learn! Love! Save the whales! Eat raw diamonds! Do the Foxtrot in your tighty-whiteys! Start fires! Kill Martians!
|
|
|
|

|
Thank you for the feedback; genuinely appreciated, especially with the pattern. I will revise the code (with credit) when I get a sec (probably on the train)... it should be there in a day or so.
|
|
|
|

|
I'm glad to help out.
:josh:
My WPF Blog[ ^]
Enjoy! Vote! Learn! Love! Save the whales! Eat raw diamonds! Do the Foxtrot in your tighty-whiteys! Start fires! Kill Martians!
|
|
|
|

|
Have submitted update; got it working using the ReflectionPermissionAttribute to do the assert, plus now fail-safes even if this fails (including rollback of dictionary so that later attempts stand a chance)
|
|
|
|

|
Great...I'm looking forward to reading the updated code and article. Nice find, regarding the ReflectionPermissionAttribute!
:josh:
My WPF Blog[ ^]
Enjoy! Vote! Learn! Love! Save the whales! Eat raw diamonds! Do the Foxtrot in your tighty-whiteys! Start fires! Kill Martians!
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
Provides a vastly accelerate runtime property implementation that can be applied even to closed-source classes
| Type | Article |
| Licence | |
| First Posted | 18 Apr 2007 |
| Views | 86,661 |
| Downloads | 1,646 |
| Bookmarked | 131 times |
|
|