Initiation values for runtime and reflection - c#

For a hobby project, I'am trying to solve the following problem:
I try to get the initialisation values with which a class instance is made also available in reflection. Currently I only know how to do this by using an attribute for reflection and the new DoubleParameter(...) to set the values runtime:
[MyDoubleSettings(-10,10,5)]
public DoubleParameter param2 = new DoubleParameter(-10,10,5);
I would like to know if there is some way to only have these values in the code once. This construct will be used many times and someone is bound to only change one or the other.
I couldn't find a way to use reflection to see the new DoubleParameter(...) values. Also I couldn't find a way to see the attribute from the DoubleParameter class.
Is there any way to do this or is there some other neat way to solve this?
Kind regards,
Ernst.

You don't need an attribute.If all you want to do is to get values of some fields or properties you can do that easily using Reflection, for example if you have three public property that holds these values you can use the following:
var values = typeof(DoubleParameter)
.GetProperties()
.Select(x => x.GetValue(yourInstance))
.ToArray();
You can also cast result of GetValue to double if you sure that the type of your properties is double or filter them based on property type:
var values = typeof(DoubleParameter)
.GetProperties()
.Where(p => p.PropertyType == typeof(double))
.Select(x => (double)x.GetValue(yourInstance))
.ToArray();

To answer your question about how to get the arguments passed inside an attribute constructor:
(Also I couldn't find a way to see the attribute from the DoubleParameter class)
class Program
{
static void Main(string[] args)
{
TestClass _testClass = new TestClass();
Type _testClassType = _testClass.GetType();
// Get attributes:
// Check if the instance class has any attributes
if (_testClassType.CustomAttributes.Count() > 0)
{
// Check the attribute which matches TestClass
CustomAttributeData _customAttribute = _testClassType.CustomAttributes.SingleOrDefault(a => a.AttributeType == typeof(TestAttribute));
if (_customAttribute != null)
{
// Loop through all constructor arguments
foreach (var _argument in _customAttribute.ConstructorArguments)
{
// value will now hold the value of the desired agrument
var value = _argument.Value;
// To get the original type:
//var value = Convert.ChangeType(_argument.Value, _argument.ArgumentType);
}
}
}
Console.ReadLine();
}
}
[TestAttribute("test")]
public class TestClass
{
}
public class TestAttribute : System.Attribute
{
public TestAttribute(string _test)
{
}
}

Related

Linq query List<List<class>> Where property of class C#

Could someone suggest a way for me to select one of the lists within a parent list where one of it's elements has a certain property value?
public class HierarchyLevel
{
public string Abbreviation;
public string Name;
public string Value;
public Type LevelType;
public List<HierarchyLevel> Children = new List<HierarchyLevel>();
}
public static List<List<HierarchyLevel>> ElementaryTypes = new List<List<HierarchyLevel>>();
I am actually trying to get the List that has the LevelType field of a specific type.
You wrote:
I am actually trying to get the List that has the LevelType field of a specific type.
What do you want if you've got several HierarchyLevels with this LevelType? And what do you want if there are no HierarchyLevels at all with this LevelType?
Let's assume that you want all HierarchyLevels with this LevelType. If later on you only want the first, or the one with a certain Abbreviation (or whatever), you could always use .FirstOrDefault, or .Where. and do a ToList in the end.
Implementing it as an extension function. See Extension Methods Demystified
public static IEnumerable<HierarchyLevel> GetHierarchyLevelsWithLevelType(
this IEnumerable<HierarchyLevel> hierarchyLevels,
LevelType desiredLevelType)
{
foreach (var hierarchyLevel in hierarchyLevels)
{
if (hierarchyLevel.LevelType == desiredLevelType)
{ // found one!
yield return hierarchyLevel;
}
// using recursion: check all the Children
IEnumerable<HierarchyLevel> childrenWithDesiredLevelType = hierarchyLevel.Children
.GetHierarchyLevelsWithLevelType(desiredLevelType);
foreach(var childWithDesiredLevelType in childrenWithDesiredLevelType)
{
yield return childWithDesiredLevelType;
}
}
}
Because of the recursion all Grandchildren and their Children etc will be returned
usage:
var allSpecialHierarchies = myHierarchies.GetHierarchyLevelsWithLevelType(LevelType.Special);
// get the first:
var firstSpecialHierarchy = allSpecialHierarchies.FirstOrDefault();
// get the first three named "Shakespeare:
var threeShakesPeares = allSpecialHierarchies
.Where(hierarchyLevel => hierarchyLevel.Name == "Shakespeare")
.Take(3)
For better usage you should provide a version that has a parameter IQualityComparer<LevelType>. Let the function above call that one.
And a nice challenge: to be fully LINQ compatible, create a version with a predicate that returns a type T and an equality comparer for this type T, so that you can have all HierarchyLevels with a certain Name, or Abbreviation.
You can Solve your with the help of recursion consider example below :- I have taken sample type of String you can use any of your Type
List<List<HierarchyLevel>> sample = new List<List<HierarchyLevel>>();
Type yourType = typeOf(string);
List<HierarchyLevel> filtered = sample.Where(x => ContainsElement(x, yourType));
public void bool ContainsElement(List<HierarchyLevel> list,Type yourType)
{
if(list.Any(x => x.LevelType == yourType) //check if current node has same level type
return true;
else if(list.Childern.Count > 0) //check if current node has children if yes then call ContainsElement again
return list.Children.Any(x => ContainsElement(x,yourType));
else
return false; //else return false in last
}
Thanks to user743414 for pointing out how simple this was :)
By using a dictionary instead, I could reference to the specific list. (This is also a faster option.)
Dictionary<Type,List<HierarchyLevel>> HierarchicalData;
I can now use it with a key of 'Type':
private void UpdateGeneralData(object Entity, Dictionary<Type,List<HierarchyLevel>> TypeData)
{
CBType.Items.Clear();
foreach (var item in TypeData[Entity.GetType()])
{
CBType.Items.Add(item);
}
}
Something like this (?):
List<HierarchyLevel> var = hLevel.Select(h => h.Children.Where(c => c.Param = "desired param")).ToList();

Reflection: Property-GetValue by Class-Type (so without an instantiated Object)

In our project we have multiple so-called Projections. These Projection-classes all have a string property with a get, called ProjectionTypeName. This ProjectionTypeName should be unique for all Projections.
Today I had the problem where two Projections had the same ProjectionTypeName which caused quite a lot of trouble. So I decided to make a UnitTest to prevent this from happening again.
I use the following method to get all the Types of all the Projections:
// The excluded abstract projections
private static readonly List<Type> AbstractProjections = new List<Type>
{
typeof(AbstractRavenDbChangesProjection),
typeof(AbstractRavenDbTimelineProjection)
};
private static IEnumerable<Type> GetAllProjectionTypes()
{
return typeof(AbstractRavenDbChangesProjection)
.Assembly
.GetTypes()
.Where(x => typeof(AbstractRavenDbChangesProjection).IsAssignableFrom(x) && !x.IsInterface)
.Except(AbstractProjections)
.ToList();
}
Then I made the actual test:
[Test]
public void TestNoDuplicated()
{
var noDuplicatedList = new Dictionary<Type, string>();
var projectionTypes = GetAllProjectionTypes();
foreach (var type in projectionTypes)
{
// TODO: Get projectionTypeName-value by Projection's Type
var projectionTypeName = ??;
Assert.IsFalse(noDuplicatedList.ContainsValue(projectionTypeName),
"{0} has been found as ProjectionTypeName in two different Projections: {1} & {2}",
projectionTypeName,
noDuplicatedList.First(x => x.Value == projectionTypeName).Key,
type);
noDuplicatedList.Add(type, projectionTypeName);
}
}
I've looked around a bit and even tried a piece of code by #JohnSkeet, even though he states (and I quote):
Please don't do this. Ever. It's ghastly. It should be trampled on,
cut up into little bits, set on fire, then cut up again. Fun though,
isn't it? ;)
But it looks like this has been changed since 2012 (when the answer was posted) and .NET now gives an error when you try this kind of reflection: "System.Security.VerificationException : Operation could destabilize the runtime.".
So, my question. How do I get the value of the string-property ProjectionTypeName, when I only have the Type of the class to my disposal (and not an actual instantiated object).
If I would had an instantiated object I would be able to do something like this:
myInstantiatedObject.GetType().GetProperty("ProjectionTypeName")
.GetValue(myInstantiatedObject, null);
What about using custom attribute instead ?
[AttributeUsage(System.AttributeTargets.Class)]
public sealed class ProjectionTypeNameAttribute : Attribute
{
private string m_Name;
public string Name
{
get { return m_Name; }
}
public ProjectionTypeNameAttribute(string name)
{
m_Name = name;
}
}
[ProjectionTypeNameAttribute(ProjectionWhatever.PROJECTION_NAME)]
public class ProjectionWhatever
{
public const string PROJECTION_NAME = "Whatever";
// if you want to have property as well
public string ProjectionTypeName
{
get
{
return PROJECTION_NAME;
}
}
}
// query if type has attribute
var type = typeof(ProjectionWhatever);
var attributes = type.GetCustomAttributes(typeof(ProjectionTypeNameAttribute), false);
if (attributes != null && attributes.Length > 0)
{
var attribute = (ProjectionTypeNameAttribute)attributes[0];
// use attribute.Name
}
Ok, I've found the answer to make John Skeet's code work, based on this answer.
My problem was this line:
var dynamicMethod = new DynamicMethod("TempUglyPropertyGetMethod", typeof(string),
Type.EmptyTypes, Assembly.GetExecutingAssembly().ManifestModule);
which was missing Assembly.GetExecutingAssembly().ManifestModule as additional argument. This is my working test code:
// https://stackoverflow.com/questions/11162652/c-sharp-get-property-value-without-creating-instance/11162876#11162876
var method = type.GetProperty("ProjectionTypeName").GetGetMethod();
var dynamicMethod = new DynamicMethod("TempUglyPropertyGetMethod", typeof(string),
Type.EmptyTypes, Assembly.GetExecutingAssembly().ManifestModule);
var generator = dynamicMethod.GetILGenerator();
generator.Emit(OpCodes.Ldnull);
generator.Emit(OpCodes.Call, method);
generator.Emit(OpCodes.Ret);
var tempUglyPropertyGetMethod = (Func<string>)dynamicMethod.CreateDelegate(typeof(Func<string>));
var projectionTypeName = tempUglyPropertyGetMethod();
Once again, don't use this in an actual project. I've only used it for this test case. To once again quote #JohnSkeet:
Please don't do this. Ever. It's ghastly. It should be trampled
on, cut up into little bits, set on fire, then cut up again. Fun
though, isn't it? ;)

Getting specific properties from an object child

Struggled to come up with a decent way to ask/title this question, but will try and illustrate it as best I can.
I am working with a data structure something like this:
public Foo
{
public Bar Bar {get;set;}
}
public Bar
{
public SubTypeA TypeA {get;set;}
public SubTypeB TypeB {get;set;}
...
}
public SubTypeA
{
public int Status {get;set;}
...
}
Note that I am unable to change the data structure for this.
There are many different types in the Bar class, which all have different properties within them, but common to all of them is the property of Status.
What I need to do, is given an object of type Foo, is record the statuses for every item in the Bar object within it. Not every SubType is going to have a value every time though, some could be null.
I can sort of manage it by using a recursive function like below to loop through all the properties. It isn't ideal though I don't think as the loop could get quite large as there could be a lot of properties on each SubType.
private void GetProperties(Type classType, object instance)
{
foreach (PropertyInfo property in classType.GetProperties())
{
object value = property.GetValue(instance, null);
if (value != null)
{
if (property.Name == "Status")
{
Record(classType, value);
}
GetProperties(property.PropertyType, value);
}
}
}
Is this about the only approach that there is for such a problem?
EDIT: Going by the answer given by Selman22, I have come up with another issue wherein I am trying to create an anonymous object based on the status and name of object.
var z = instance.GetType()
.GetProperties()
.Select(x => new
{
status = x.GetValue(instance).GetType().GetProperty("status").GetValue(x, null),
name = x.Name
})
.ToList();
This is throwing an error of Object does not match target type. when trying to retrieve the value. Is this possible in a 1 liner?
Type class contains GetProperty(string name, BindingFlags method) that you can use to retrieve specific property. Instead of looping through every property use this method.
http://msdn.microsoft.com/en-us/library/system.type.getproperty(v=vs.110).aspx
// Get Type object of MyClass.
Type myType=typeof(MyClass);
// Get the PropertyInfo by passing the property name and specifying the BindingFlags.
PropertyInfo myPropInfo = myType.GetProperty("MyProperty", BindingFlags.Public | BindingFlags.Instance);
You can get all Status properties using LINQ instead of recursion:
var barInstance = typeof(Foo).GetProperty("Bar").GetValue(fooInstance);
var statusProperties = barInstance.GetType()
.GetProperties()
.Select(x => x.GetValue(barInstance).GetType().GetProperty("Status"));

How can I use custom-attributes in C# to replace switches in switches?

I have a factory method that returns the correct sub class depending on three enum values.
One way to do is, would be to use switches in switches in switches. Obviously, I don't like that option very much.
I thought that another option would be to use attributes in C#. Every sub class would have an attribute with that 3 enum values and in the factory I would only have to get the class that has the same enum values corresponding to the enum values i have in the factory.
However, I am quite new to attributes and I did not find any suitable solution in the web. If anyone, could just give me some hints or some lines of code, I really would appreciate that!
First of all, declare your attribute and add it to your classes.
enum MyEnum
{
Undefined,
Set,
Reset
}
class MyEnumAttribute : Attribute
{
public MyEnumAttribute(MyEnum value)
{
Value = value;
}
public MyEnum Value { get; private set; }
}
[MyEnum(MyEnum.Reset)]
class ResetClass
{
}
[MyEnum(MyEnum.Set)]
class SetClass
{
}
[MyEnum(MyEnum.Undefined)]
class UndefinedClass
{
}
Then, you can use this code to create a dictionary with your enums and types, and dynamically create a type.
//Populate a dictionary with Reflection
var dictionary = Assembly.GetExecutingAssembly().GetTypes().
Select(t => new {t, Attribute = t.GetCustomAttribute(typeof (MyEnumAttribute))}).
Where(e => e.Attribute != null).
ToDictionary(e => (e.Attribute as MyEnumAttribute).Value, e => e.t);
//Assume that you dynamically want an instance of ResetClass
var wanted = MyEnum.Reset;
var instance = Activator.CreateInstance(dictionary[wanted]);
//The biggest downside is that instance will be of type object.
//My solution in this case was making each of those classes implement
//an interface or derive from a base class, so that their signatures
//would remain the same, but their behaviors would differ.
As you can probably notice, calling Activator.CreateInstance is not performant. Therefore, if you want to improve the performance a little bit, you can change the dictionary to Dictionary<MyEnum,Func<object>> and instead of adding types as values you would add functions wrapping the constructor of each of your classes and returning them as objects.
EDIT: I'm adding a ConstructorFactory class, adapted from this page.
static class ConstructorFactory
{
static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
{
var paramsInfo = ctor.GetParameters();
var param = Expression.Parameter(typeof(object[]), "args");
var argsExp = new Expression[paramsInfo.Length];
for (var i = 0; i < paramsInfo.Length; i++)
{
Expression index = Expression.Constant(i);
var paramType = paramsInfo[i].ParameterType;
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
argsExp[i] = paramCastExp;
}
var newExp = Expression.New(ctor, argsExp);
var lambda = Expression.Lambda(typeof(ObjectActivator<T>), newExp, param);
var compiled = (ObjectActivator<T>)lambda.Compile();
return compiled;
}
public static Func<T> Create<T>(Type destType)
{
var ctor = destType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).First();
Func<ConstructorInfo, object> activatorMethod = GetActivator<Type>;
var method = typeof(ConstructorFactory).GetMethod(activatorMethod.Method.Name, BindingFlags.Static | BindingFlags.NonPublic);
var generic = method.MakeGenericMethod(destType);
dynamic activator = generic.Invoke(null, new object[] { ctor });
return () => activator();
}
delegate T ObjectActivator<out T>(params object[] args);
}
You can use it as an alternative to Activator.CreateInstance, it provides greater performance if the result is cached.
var dictionary = Assembly.GetExecutingAssembly().GetTypes().
Select(t => new { t, Attribute = t.GetCustomAttribute(typeof(MyEnumAttribute)) }).
Where(e => e.Attribute != null).
ToDictionary(e => (e.Attribute as MyEnumAttribute).Value,
e => ConstructorFactory.Create<object>(e.t));
var wanted = MyEnum.Reset;
var instance = dictionary[wanted]();
Have a look at this article: Creating Custom Attributes. You can then use reflection (for instance GetCustomAttributes) to get the attributes and their values.
Hope this helps
[AttributeUsage(AttributeTargets.Class)]
public class SampleClass : Attribute {
public SampleClass() : base() { }
public SampleClass(YourEnum attributeValue) : this() { MyAttributeProperty = attributeValue; }
public YourEnum MyAttributeProperty { get; set; }
}
public enum YourEnum { Value1, Value2, Value3 }
[SampleClass(YourEnum.Value1)]
public class ExampleValue1Class { }
public class LoadOnlyClassesWithEnumValue1 {
public LoadOnlyClassesWithEnumValue1() {
Type[] allTypes = Assembly.GetExecutingAssembly().GetExportedTypes();
foreach (var type in allTypes) {
if (type.GetCustomAttributes(typeof(SampleClass), false).Length > 0) {
SampleClass theAttribute = type.GetCustomAttributes(typeof(SampleClass), false).Single() as SampleClass;
// this type is using SampleClass - I use .Single() cause I don't expect multiple SampleClass attributes, change ths if you want
// specify true instead of false to get base class attributes as well - i.e. ExampleValue1Class inherits from something else which has a SampleClass attribute
switch (theAttribute.MyAttributeProperty) {
case YourEnum.Value1:
// Do whatever
break;
case YourEnum.Value2:
// you want
break;
case YourEnum.Value3:
default:
// in your switch here
// You'll find the ExampleValue1Class object should hit the Value1 switch
break;
}
}
}
}
}
This way you can specify your enum as a parameter to the attribute. In essence, this is a very simple and lightweight DI container.
I'd suggest for anything more complex, to use something like StructureMap or NInject.
Another solution would be to use Dependency Injection (DI) container. For instance using Unity DI you can:
// Register a named type mapping
myContainer.RegisterType<IMyObject, MyRealObject1>(MyEnum.Value1.ToString());
myContainer.RegisterType<IMyObject, MyRealObject2>(MyEnum.Value2.ToString());
myContainer.RegisterType<IMyObject, MyRealObject3>(MyEnum.Value3.ToString());
// Following code will return a new instance of MyRealObject1
var mySubclass = myContainer.Resolve<IMyObject>(myEnum.Value1.ToString());
Examples on using Unity:
Implementing the Microsoft Unity (Dependency Injection) Design Pattern
Of course you can use any DI container (Castle Windsor, StructureMap, Ninject. Here is a list some of the available .NET DI containers List of .NET Dependency Injection Containers (IOC)
It is possible to use attributes to hold the information, but ultimately the decision process will still have to be made and will likely not be much different; just with the added complexity of the attributes. The nature of the decision remains the same regardless of where you get the information to make the decision, from the existing three enumerations or from attributes.
It may prove more fruitful to look for a way to combine the three enumerations.
Enums can be any integral type, so the easiest way to eliminate nested (and redundant) switches is to combine the enumerations together. This is easiest if the enumeration is a collection of flag values. That is, each value of the enumeration has the value of a single bit in a binary string (1 for the first bit, 2 for the second bit, 4 for the third, 8, 16 and so on).
Provided the values of each of the enumerations can be joined together it reduces the selection process to a single switch statement. This may be best done by concatenating, multiplying or adding the enumeration values -- but how they are joined together depends on the enumerations, and without knowing more details it is hard to provide more definite direction.

Property Type as Generic parameter

I'm trying to figure out how I can make a Generics call take a variable for the Type. In the call below it take a type "DAL.Account" and works fine.
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
I want to change that so that I can pass a variable in place of the "DAL.Account". Something like this but I know that won't work as you can't pass property as a Type.
ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray())
Below is the shell pieces of code I think explains what I'm trying to do. Generics is not my strong suit so I'm looking for some help. Is there anyway that I can make this happen?
//Stores a "Type" that indicates what Object is a Criteria for.
public class AccountCriteria : IGeneratedCriteria
{
...
public Type EntityType
{
get {return typeof(DAL.Account);}
}
}
//I have added a function to the DataContext called "GetTable"
// And then used it as an example in a Console App to test its functionality.
public class ADRPDataContext : NHibernateDataContext
{
...
public CodeSmith.Data.NHibernate.ITable<T> GetTable<T>() where T : EntityBase
{
var tb = new CodeSmith.Data.NHibernate.Table<T>(this);
return tb;
}
}
// console application that uses DataContext.GetTable
class Program
{
static void Main(string[] args)
{
using (var ctx = new ADRPDataContext())
{
var tst = ctx.GetTable<DAL.Account>().Where(t => t.Sbank == "000134");
}
}
}
//ExistsCommand class that uses the EntityType property of the Critera to generate the data.
public class ExistsCommand
{
private IGeneratedCriteria Criteria { get; set; }
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
//This was my first attempt but doesn't work becuase you can't pass a property in for a Type.
//But I can figure out how to write this so that it will work.
Result = ctx.GetTable<Criteria.EntityType>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
You are looking to instantiate a generic type. Some info can be found here
This is a simple example demonstrating how to instantiate a List with a capacity of 3. Here is a method that you can call to create a generic when you don't know the type:
public static Object CreateGenericListOfType(Type typeGenericWillBe)
{
//alternative to the followin:
//List<String> myList = new List<String>(3);
//build parameters for the generic's constructor (obviously this code wouldn't work if you had different constructors for each potential type)
object[] constructorArgs = new Object[1];
constructorArgs[0] = 3;
//instantiate the generic. Same as calling the one line example (commented out) above. Results in a List<String> with 3 list items
Type genericListType = typeof(List<>);
Type[] typeArgs = { typeGenericWillBe };
Type myNewGeneric = genericListType.MakeGenericType(typeArgs);
object GenericOfType = Activator.CreateInstance(myNewGeneric, constructorArgs);
return GenericOfType;
}
And here is some sample code that will show you the example method works:
List<String> Strings = (List<String>)InstantiateGenericTypeWithReflection.CreateGenericListOfType(typeof(String));
//demonstrate the object is actually a List<String> and we can do stuff like use linq extensions (isn't a good use of linq but serves as example)
Strings.Add("frist");
Strings.Add("2nd");
Strings.Add("tird");
Console.WriteLine("item index 2 value: " + Strings.Where(strings => strings == "2").First());
In your example, replace your GetTable<Criteria.EntityType>() with CreateGenericTableOfType(Criteria.EntityType). This will return a generic table of whatever type you pass in. You will of course need to implement the method properly (handle constructor args, change List to Table etc).
I think you need to change the way you're doing this slightly, and instead use generics instead of the EntityType property. Perhaps something along the lines of the following:
// Create an abstract class to be used as the base for classes that are supported by
// ExistsCommand and any other classes where you need a similar pattern
public abstract class ExtendedCriteria<T> : IGeneratedCriteria
{
public ExistsCommand GetExistsCommand()
{
return new ExistsCommand<T>(this);
}
}
// Make the non-generic ExistsCommand abstract
public abstract class ExistsCommand
{
protected abstract void DataPortal_Execute();
}
// Create a generic sub-class of ExistsCommand with the type parameter used in the GetTable call
// where you were previously trying to use the EntityType property
public class ExistsCommand<T> : ExistsCommand
{
protected override void DataPortal_Execute()
{
using (var ctx = new DC.ADRPDataContext())
{
Result = ctx.GetTable<T>().Where(LinqToSQLHelper.BuildWhereStatement(Criteria.StateBag), Criteria.StateBag.Values.ToArray()).Count() > 0;
}
}
}
// Derive the AccountCriteria from ExtendedCriteria<T> with T the entity type
public class AccountCriteria : ExtendedCriteria<DAL.Account>
{
...
}

Categories

Resources