Reputation: 9326
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);
Upvotes: 1
Views: 274
Reputation: 22054
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
}
Upvotes: 2
Reputation: 9326
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? ;)
Upvotes: 1