Dynamically convert property to Type - c#

Is it possible to simplify this logic, Is there generic way to do it.
The code finds marked attributes and parses it according to the attribute type.
Please suggest some way to optimize this code, all the data type of Product class will be string, I'm getting product input as xml directly converting serialized data to a class with decimal,int,float will not give proper error message, If there is list of item it throws error in xml we wont know which row has caused the error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace TestSolution
{
public interface ICustomParser
{
bool Parse(string input);
}
public class DecimalParserAttribute : Attribute, ICustomParser
{
public bool Parse(string input)
{
if (input == null) return false;
decimal decimalValue;
return decimal.TryParse(input, out decimalValue);
}
}
public class intParserAttribute : Attribute, ICustomParser
{
public bool Parse(string input)
{
if (input == null) return false;
int intValue;
return int.TryParse(input, out intValue);
}
}
public class Product
{
[DecimalParser]
public string Weight { get; set; }
[intParser]
public string NoOfItems { get; set; }
[intParser]
public string GRodes { get; set; }
[intParser]
public string WRodes { get; set; }
}
class Program
{
static void Main(string[] args)
{
var sb = Validate(new Product() { NoOfItems = "1", GRodes = "4", Weight = "5", WRodes = "23" });
Console.WriteLine(sb);
sb = Validate(new Product() { NoOfItems = "1", GRodes = "4w", Weight = "5", WRodes = "23" });
Console.WriteLine(sb);
Console.ReadKey();
}
private static string Validate(Product product)
{
var sb = new StringBuilder();
foreach (var property in product.GetType().GetProperties())
{
var value = Convert.ToString(property.GetValue(product, null));
var sel = property.GetAttribute<ICustomParser>();
if (sel == null) continue;
var parserinstance = (ICustomParser)Activator.CreateInstance(sel.GetType());
if (parserinstance.Parse(value)) continue;
sb.AppendLine(string.Format("{0} Has invalid value", property.Name));
}
return sb.ToString();
}
}
public static class Extensions
{
public static T GetAttribute<T>(this PropertyInfo property)
{
return (T)property.GetCustomAttributes(false).Where(s => s is T).FirstOrDefault();
}
}
}

If you only have one type (Product), it probably isn't worth it - just write the validation code explicitly without all the fancy stuff. If, however, you have multiple types to inspect (perhaps known only at runtime):
It really depends how fast it needs to be. How often does this run? If it is periodic, then there isn't a vast amount to do - the main change would be to just cast the parser directly:
var parserInstance = (ICustomParser)sel;
(it already is the attribute type)
If it is critical path, then there is a lot you can do to beef it up, but you get into the realm of metaprogramming - which is essentially what most tools like serializers and ORMs do to reduce runtime reflection. If you're not familiar with hacking IL at runtime, I would recommend looking at a tool like "Sigil" (available on nuget) that makes it hard to get wrong (or at least: tells you what you've done wrong). Essentially, you can inspect the data structure and then emit the IL that matches what it would look like if you were doing it all in explicit code; for example, emitting IL that looks kinda like:
static readonly DecimalParserAttribute _decimal = new DecimalParserAttribute();
public static void Validate(Product product) {
var sb = new StringBuilder();
if(!_decimal.Parse(product.Weight)) {
sb.Append(...);
}
// ... etc
...,
}

Related

Map [name,value] string values to class without reflection

I'm having a huge performance issue about mapping string property names and string property values to classes using reflection.
My issue now:
public class Person
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public string Property4 { get; set; }
// My class has around 100 properties
public string Property100 { get; set; }
}
I am mapping a key value pair collection to the class using reflection
[{"Property1": "some value"}, {"Property2": "something else"},{"Property3","Property4","value" }.....{"Property100","val"}]
It got to the point that I am now mapping around 10 000 class instances using reflection and the performance is to say it lightly bad.
Any ideas for eliminating the reflection would be greatly appreciated.
I see two options, if you need to avoid reflection for tasks like this(when code could be programatically generated).
First is Expressions I use it often, e.g. I saw some people write something like this
public class A
{
public Prop1 ...
....
public Prop100
public override ToString() => $"{nameof(Prop1)}={Prop1};...";
and so for all 100 properties, and always doing this manually.
And with Expression it can be easily automated, you just need to generate Expression for String.Concat and pass list of properties and names there.
For your example, it is not clear what are your data. How do you do lookup in the list?
Let's assume there is a dictionary<string,string>(you can transform your list of tuples to a dictionary), and all properties are strings as well.
Then we would need to generate a list assignment expressions like this
if(data.ContainsKey("Prop1")) result.Prop1 = data["Prop1"];
And the code would be complicated, anyway it would look like this
private static class CompiledDelegate<T>
{
public static Action<T, Dictionary<string, string>> initObject;
static CompiledDelegate()
{
var i = Expression.Parameter(typeof(Dictionary<string, string>), "i");
var v = Expression.Parameter(typeof(T), "v");
var propertyInfos = typeof(T).GetProperties().ToArray();
var t = new Dictionary<string, string>();
var contains = typeof(Dictionary<string, string>).GetMethod(nameof(Dictionary<string, string>.ContainsKey));
var getter = typeof(Dictionary<string, string>).GetProperties().First(x => x.GetIndexParameters().Length > 0);
var result = new List<Expression>();
foreach (var propertyInfo in propertyInfos)
{
var cst = Expression.Constant(propertyInfo.Name);
var assignExpression =
Expression.IfThen(Expression.Call(i, contains, cst),
Expression.Assign(Expression.PropertyOrField(v, propertyInfo.Name), Expression.MakeIndex(i, getter, new[] { cst })));
result.Add(assignExpression);
}
var block = Expression.Block(result);
initObject = Expression.Lambda<Action<T, Dictionary<string, string>>>(block, new ParameterExpression[] { v, i }).Compile();
}
}
It is an example, it would fail if there were non-string properties.
And it could be used like this
static void Main(string[] args)
{
var tst = new Test();
CompiledDelegate<Test>.initObject(tst, new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S2", "Value2" },
});
CompiledDelegate<Test>.initObject(tst, new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S1", "Value1" },
});
Console.ReadKey();
}
The second option is, actually, what it should be ideally imlemented like Using source generators I think such things do have to be done just in build time.
There is a lot of articles on msdn, for instance with samples. But it turned out to be not very easy to implement, even just a sample.
I can say, it didn't work for me, while I tried to do it according to samples.
In order to get it work I had to change TargetFramework to netstandard2.0, do something else...
But after all, when build was green, Visual Studio still showed an error.
Ok, it disappeared after VS restart, but still, that doesn't look very usable.
So, this is a generator, that creates a converter for every class with attribute.
It is again a sample, it doesn't check many things.
[Generator]
public class ConverterGenerator : ISourceGenerator
{
private static string mytemplate = #"using System.Collections.Generic;
using {2};
namespace GeneratedConverters
{{
public static class {0}Converter
{{
public static {0} Convert(Dictionary<string, string> data)
{{
var result = new {0}();
{1}
return result;
}}
}}
}}";
public static string GetNamespaceFrom(SyntaxNode s)
{
if (s.Parent is NamespaceDeclarationSyntax namespaceDeclarationSyntax)
{
return namespaceDeclarationSyntax.Name.ToString();
}
if (s.Parent == null)
return "";
return GetNamespaceFrom(s.Parent);
}
public void Execute(GeneratorExecutionContext context)
{
GetMenuComponents(context, context.Compilation);
}
private static void GetMenuComponents(GeneratorExecutionContext context, Compilation compilation)
{
var allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes());
var allClasses = allNodes.Where(d => d.IsKind(SyntaxKind.ClassDeclaration)).OfType<ClassDeclarationSyntax>();
var classes = allClasses
.Where(c => c.AttributeLists.SelectMany(a => a.Attributes).Select(a => a.Name).Any(s => s.ToString().Contains("DictionaryConverter")))
.ToImmutableArray();
foreach (var item in classes.Distinct().Take(1))
{
context.AddSource(item.Identifier.Text + "Converter", String.Format(mytemplate, item.Identifier.Text, SourceText.From(GenerateProperties(item)), GetNamespaceFrom(item)));
}
}
private static string GenerateProperties(ClassDeclarationSyntax s)
{
var properties = s.Members.OfType<PropertyDeclarationSyntax>();
return String.Join(Environment.NewLine,
properties.Select(p =>
{
var name = p.Identifier.Text;
return $"if(data.ContainsKey(\"{name}\")) result.{name} = data[\"{name}\"];";
}));
}
public void Initialize(GeneratorInitializationContext context)
{
}
}
and
static void Main(string[] args)
{
var t1 = GeneratedConverters.TestConverter.Convert(new Dictionary<string, string>
{
{ "S3", "Value3" },
{ "S2", "Value2" },
});
}
Best performance without reflection would be manual mapping.
It seems your key/value pair collection is regular JSON. So you could use the JSONTextReader from JSON.NET and read the string. Then manually map the JSON properties to the class properties.
Like so:
JsonTextReader reader = new JsonTextReader(new StringReader(jsonString));
while (reader.Read())
{
if (reader.Value != null)
{
// check reader.Value.ToString() and assign to correct class property
}
}
More info can be found on the JSON.NET website : https://www.newtonsoft.com/json/help/html/ReadingWritingJSON.htm

How to get the base class name of a class via Roslyn?

I am using Roslyn and I have the following class:
var source = #"
using System;
class MyClass : MyBaseClass {
static void Main(string[] args) {
Console.WriteLine(""Hello, World!"");
}
}";
// Parsing
SyntaxTree tree = CSharpSyntaxTree.ParseText(source);
// This uses an internal function (working)
// That gets the first node of type `SimpleBaseTypeSyntax`
SimpleBaseTypeSyntax simpleBaseType = GetNBaseClassNode(tree);
Getting the base class name
I successfully get access to node SimpleBaseTypeSyntax which contains what I need. In fact, if I use the syntax explorer, I get:
Node IdentifierToken has everything I need has its Text, Value and ValueText properties are "MyBaseClass"!
However, while in the syntax explorer I can see all these values, I cannot access them programmatically.
So I try retrieving the node programmatically:
IdentifierNameSyntax identifierNode =
simpleBaseType.ChildNodes().OfType<IdentifierNameSyntax>().First();
SyntaxToken identifier = simpleBaseType.Identifier;
string name = identifier.Text;
But name is empty string. Same as identifier.Value and identifier.ValueText.
What am I doing wrong? Maybe I am doing wrong, so how would you retrieve the base class name?
Another attempt: Using the semantic model
I started thinking that I need the semantic model for this type of information:
IdentifierNameSyntax identifierNode =
simpleBaseType .ChildNodes().OfType<IdentifierNameSyntax>().First();
SemanticModel semanticModel =
CSharpCompilation.Create("Class")
.AddReferences(MetadataReference.CreateFromFile(
typeof(object).Assembly.Location))
.AddSyntaxTrees(tree).GetSemanticModel(tree);
SymbolInfo symbolInfo = this.semanticModel.GetSymbolInfo(identifierNode);
string name = symbolInfo.Symbol.Name;
This throws exception as symbolInfo.Symbol is null.
I actually don't know why you can't pass the BaseTypeSyntax to the semantic model via GetSymbolInfo(), but it's also returning null for me with no errors.
Anyways, here's an approach that works:
var tree = CSharpSyntaxTree.ParseText(#"
using System;
class MyBaseClass
{
}
class MyClass : MyBaseClass {
static void Main(string[] args) {
Console.WriteLine(""Hello, World!"");
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var myClass = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().Last();
var myClassSymbol = model.GetDeclaredSymbol(myClass) as ITypeSymbol;
var baseTypeName = myClassSymbol.BaseType.Name;
You'll want to use the semantic model here because you won't be able to reliably tell if you're dealing with an interface or a base type at the syntax level.
I can see that you're trying to build an analyzer with the Roslyn API.
You do know that there are other ways to test your analyzer logic? Using unit test files instead of directly having the source inside the analyzer.
Using this idea, you entirely build your analyzer with the template provided by Visual Studio, where you must inherit from DiagnosticAnalyzer and you create your analysis code logic.
For your situation, you should look at ClassDeclaration and easily access the BaseTypes property inside the Node.
public bool SomeTriedDiagnosticMethod(SyntaxNodeAnalysisContext nodeContext)
{
var classDeclarationNode = nodeContext.Node as ClassDeclarationSyntax;
if (classDeclarationNode == null) return false;
var baseType = classDeclarationNode.BaseList.Types.FirstOrDefault(); // Better use this in all situations to be sure code won't break
var nameOfFirstBaseType = baseType.Type.ToString();
return nameOfFirstBaseType == "BaseType";
}
protected static bool IsWebPage(SyntaxNodeAnalysisContext context, ClassDeclarationSyntax classDeclaration)
{
INamedTypeSymbol iSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclaration) as INamedTypeSymbol;
INamedTypeSymbol symbolBaseType = iSymbol?.BaseType;
while (symbolBaseType != null)
{
if (symbolBaseType.ToString() == "System.Web.UI.Page")
return true;
symbolBaseType = symbolBaseType.BaseType;
}
return false;
}
This is my helper class that finds all properties, class name, class namespace and base classes.
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
namespace MyProject
{
public class CsharpClass
{
public string Name { get; set; }
public string Namespace { get; set; }
public List<CsharpProperty> Properties { get; set; }
public List<string> BaseClasses { get; set; }
public class CsharpProperty
{
public string Name { get; set; }
public string Type { get; set; }
public CsharpProperty(string name, string type)
{
Name = name;
Type = type;
}
}
public CsharpClass()
{
Properties = new List<CsharpProperty>();
BaseClasses = new List<string>();
}
}
public static class CsharpClassParser
{
public static CsharpClass Parse(string content)
{
var csharpClass = new CsharpClass();
var tree = CSharpSyntaxTree.ParseText(content);
var members = tree.GetRoot().DescendantNodes().OfType<MemberDeclarationSyntax>();
foreach (var member in members)
{
if (member is PropertyDeclarationSyntax property)
{
csharpClass.Properties.Add(new CsharpClass.CsharpProperty(
property.Identifier.ValueText, property.Type.ToString()));
}
if (member is NamespaceDeclarationSyntax namespaceDeclaration)
{
csharpClass.Namespace = namespaceDeclaration.Name.ToString();
}
if (member is ClassDeclarationSyntax classDeclaration)
{
csharpClass.Name = classDeclaration.Identifier.ValueText;
csharpClass.BaseClasses = GetBaseClasses(classDeclaration).ToList();
}
//if (member is MethodDeclarationSyntax method)
//{
// Console.WriteLine("Method: " + method.Identifier.ValueText);
//}
}
return csharpClass;
}
private static IEnumerable<string> GetBaseClasses(ClassDeclarationSyntax classDeclaration)
{
if (classDeclaration == null)
{
return null;
}
if (classDeclaration.BaseList == null)
{
return null;
}
return classDeclaration.BaseList.Types.Select(x => x.Type.ToString());
}
}
}
Usage:
const string content = #"
namespace Acme.Airlines.AirCraft
{
public class AirCraft
{
public virtual string Name { get; set; }
public virtual int Code { get; set; }
public AirCraft()
{
}
}
}";
var csharpClass = CsharpClassParser.Parse(content);
Console.WriteLine(csharpClass.Name);
Console.WriteLine(csharpClass.Namespace);
Console.WriteLine(csharpClass.Properties.Count);
Console.WriteLine(csharpClass.BaseClasses.Count);

Dapper. Map to SQL Column with spaces in column names

I've managed to get something up and running today as small sandbox/POC project, but have seemed to bump my head on one issue...
Question:
Is there a way to get dapper to map to SQL column names with spaces in them.
I have something to this effect as my result set.
For example:
SELECT 001 AS [Col 1],
901 AS [Col 2],
00454345345345435349 AS [Col 3],
03453453453454353458 AS [Col 4]
FROM [Some Schema].[Some Table]
And my class would look like this
public class ClassA
{
public string Col1 { get; set; }
public string Col2 { get; set; }
///... etc
}
My implementation looks like this at the moment
public Tuple<IList<TClass>, IList<TClass2>> QueryMultiple<TClass, TClass2>(object parameters)
{
List<TClass> output1;
List<TClass2> output2;
using (var data = this.Connection.QueryMultiple(this.GlobalParameter.RpcProcedureName, parameters, CommandType.StoredProcedure))
{
output1 = data.Read<TClass>().ToList();
output2 = data.Read<TClass2>().ToList();
}
var result = new Tuple<IList<TClass>, IList<TClass2>>(output1, output2);
return result;
}
Note: The SQL cant be modified in any way.
Currently I'm going through the dapper code, and my only foreseeable solution is to add some code to "persuade" the column comparison, but not having much luck so far.
I've seen on StackOverflow that there are things like dapper extensions, but I'm hoping I can get this done without adding an extention, if not. I'll take whatever is quickest to implement.
There's a nuget package Dapper.FluentMap that allows you to add column name mappings (including spaces). It's similar to EntityFramework.
// Entity class.
public class Customer
{
public string Name { get; set; }
}
// Mapper class.
public class CustomerMapper : EntityMap<Customer>
{
public CustomerMapper()
{
Map(p => p.Name).ToColumn("Customer Name");
}
}
// Initialise like so -
FluentMapper.Initialize(a => a.AddMap(new CustomerMapper()));
see https://github.com/henkmollema/Dapper-FluentMap for more.
One option here would be to go via the dynamic / non-generic API, and then fetch the values out via the IDictionary<string,object> API per row, but that might be a bit tedious.
As an alternative, you can create a custom mapper, and tell dapper about it; for example:
SqlMapper.SetTypeMap(typeof(ClassA), new RemoveSpacesMap());
with:
class RemoveSpacesMap : Dapper.SqlMapper.ITypeMap
{
System.Reflection.ConstructorInfo SqlMapper.ITypeMap.FindConstructor(string[] names, Type[] types)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetConstructorParameter(System.Reflection.ConstructorInfo constructor, string columnName)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetMember(string columnName)
{
var prop = typeof(ClassA).GetProperty(columnName.Replace(" ", ""));
return prop == null ? null : new PropertyMemberMap(columnName, prop);
}
class PropertyMemberMap : Dapper.SqlMapper.IMemberMap
{
private string columnName;
private PropertyInfo property;
public PropertyMemberMap(string columnName, PropertyInfo property)
{
this.columnName = columnName;
this.property = property;
}
string SqlMapper.IMemberMap.ColumnName
{
get { throw new NotImplementedException(); }
}
System.Reflection.FieldInfo SqlMapper.IMemberMap.Field
{
get { return null; }
}
Type SqlMapper.IMemberMap.MemberType
{
get { return property.PropertyType; }
}
System.Reflection.ParameterInfo SqlMapper.IMemberMap.Parameter
{
get { return null; }
}
System.Reflection.PropertyInfo SqlMapper.IMemberMap.Property
{
get { return property; }
}
}
}
I had a similar problem when trying to get mapped results from a call to the system sp_spaceused procedure. Marc's code didn't quite work for me as it complained about not being able to find a default constructor. I also made my version generic so it could theoretically be re-used. This may not be the fastest performing piece of code, but it works for me and in our situation these calls are made infrequently.
class TitleCaseMap<T> : SqlMapper.ITypeMap where T: new()
{
ConstructorInfo SqlMapper.ITypeMap.FindConstructor(string[] names, Type[] types)
{
return typeof(T).GetConstructor(Type.EmptyTypes);
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetConstructorParameter(ConstructorInfo constructor, string columnName)
{
return null;
}
SqlMapper.IMemberMap SqlMapper.ITypeMap.GetMember(string columnName)
{
string reformattedColumnName = string.Empty;
foreach (string word in columnName.Replace("_", " ").Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
reformattedColumnName += char.ToUpper(word[0]) + word.Substring(1).ToLower();
}
var prop = typeof(T).GetProperty(reformattedColumnName);
return prop == null ? null : new PropertyMemberMap(prop);
}
class PropertyMemberMap : SqlMapper.IMemberMap
{
private readonly PropertyInfo _property;
public PropertyMemberMap(PropertyInfo property)
{
_property = property;
}
string SqlMapper.IMemberMap.ColumnName
{
get { throw new NotImplementedException(); }
}
FieldInfo SqlMapper.IMemberMap.Field
{
get { return null; }
}
Type SqlMapper.IMemberMap.MemberType
{
get { return _property.PropertyType; }
}
ParameterInfo SqlMapper.IMemberMap.Parameter
{
get { return null; }
}
PropertyInfo SqlMapper.IMemberMap.Property
{
get { return _property; }
}
}
}
I know this is an old question nevertheless i faced the same problem in my last project, so i just created an own mapper using attributes.
I defined an attribute class called ColumnNameAttribute.cs
using System;
namespace DapperHelper.Attributes
{
[System.AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
sealed class ColumNameAttribute : Attribute
{
private string _columName;
public string ColumnName
{
get { return _columName; }
set { _columName = value; }
}
public ColumNameAttribute(string columnName)
{
_columName = columnName;
}
}
}
After defining the attribute, i implemeted a dynamic mapper that uses the Query method from Dapper but works as the Query<T>:
using Dapper;
using DapperHelper.Attributes;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Web.Routing;
namespace DapperHelper.Tools
{
public class DynamicMapper<T> :IDisposable where T : class, new()
{
private readonly Dictionary<string, PropertyInfo> _propertiesMap;
public DynamicMapper()
{
_propertiesMap = new Dictionary<string, PropertyInfo>();
PropertyInfo[] propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo propertyInfo in propertyInfos)
{
if (propertyInfo.GetCustomAttribute(typeof(ColumNameAttribute)) is ColumNameAttribute columNameAttribute)
{
_propertiesMap.Add(columNameAttribute.ColumnName, propertyInfo);
}
else
{
_propertiesMap.Add(propertyInfo.Name, propertyInfo);
}
}
}
public List<T> QueryDynamic(IDbConnection dbConnection, string sqlQuery)
{
List<dynamic> results = dbConnection.Query(sqlQuery).ToList();
List<T> output = new List<T>();
foreach (dynamic dynObj in results)
{
output.Add(AssignPropertyValues(dynObj));
}
return output;
}
private T AssignPropertyValues(dynamic dynamicObject)
{
T output = new T();
RouteValueDictionary dynamicObjProps = new RouteValueDictionary(dynamicObject);
foreach (var propName in dynamicObjProps.Keys)
{
if (_propertiesMap.TryGetValue(propName, out PropertyInfo propertyMapped)
&& dynamicObjProps.TryGetValue(propName, out object value))
{
propertyMapped.SetValue(output, value);
}
}
return output;
}
public void Dispose()
{
_propertiesMap.Clear();
}
}
}
To use it, you have to refer to your Model class and define the attribute:
using DapperHelper.Attributes;
namespace Testing
{
public class Sample
{
public int SomeColumnData { get; set; }
[ColumnName("Your Column Name")]
public string SpecialColumn{ get; set; }
}
}
and then you can implement something like this:
DynamicMapper<Sample> mapper = new DynamicMapper<Sample>();
List<Sample> samples = mapper.QueryDynamic(connection, "SELECT * FROM Samples");
I hope it can help someone looking for an alternative.

Is it possible to modify the attribute of a property at runtime?

Is it possible to modify the attribute of a property at runtime?
let's say I have some class:
public class TheClass
{
[TheAttribute]
public int TheProperty { get; set; }
}
Is there a way to do this?
if (someCondition)
{
// disable attribute. Is this possible and how can this be done?
}
No this is not possible. You cannot modify attribute values from metadata, or metadata in general, at runtime
Strictly speaking the above is not true. There are certain APIs which do allow allow for some metadata generation and modification. But they are very scenario specific, (ENC, profiling, debugging) and should not be used in general purpose programs.
It depends; from a reflection perspective: no. You can't. But if you are talking about attributes used by System.ComponentModel in things like data-binding, they you can use TypeDescriptor.AddAttributes to append extra attributes. Or other customer models involving custom descriptors. So it depends on the use-case.
In the case of xml serialization, it gets more interesting. Firstly, we can use fun object models:
using System;
using System.Xml.Serialization;
public class MyData
{
[XmlAttribute]
public int Id { get; set; }
[XmlAttribute]
public string Name { get; set; }
[XmlIgnore]
public bool NameSpecified { get; set; }
static void Main()
{
var ser = new XmlSerializer(typeof(MyData));
var obj1 = new MyData { Id = 1, Name = "Fred", NameSpecified = true };
ser.Serialize(Console.Out, obj1);
Console.WriteLine();
Console.WriteLine();
var obj2 = new MyData { Id = 2, Name = "Fred", NameSpecified = false };
ser.Serialize(Console.Out, obj2);
}
}
The bool {name}Specified {get;set;} pattern (along with bool ShouldSerialize{name}()) is recognised and used to control which elements to include.
Another alternative is to use the non-default ctor:
using System;
using System.Xml.Serialization;
public class MyData
{
[XmlAttribute]
public int Id { get; set; }
public string Name { get; set; }
static void Main()
{
var obj = new MyData { Id = 1, Name = "Fred" };
XmlAttributeOverrides config1 = new XmlAttributeOverrides();
config1.Add(typeof(MyData),"Name",
new XmlAttributes { XmlIgnore = true});
var ser1 = new XmlSerializer(typeof(MyData),config1);
ser1.Serialize(Console.Out, obj);
Console.WriteLine();
Console.WriteLine();
XmlAttributeOverrides config2 = new XmlAttributeOverrides();
config2.Add(typeof(MyData), "Name",
new XmlAttributes { XmlIgnore = false });
var ser2 = new XmlSerializer(typeof(MyData), config2);
ser2.Serialize(Console.Out, obj);
}
}
Note though that if you use this second approach you need to cache the serializer instance, as it emits an assembly every time you do this. I find the first approach simpler...
Attributes are baked into code at compilation time. The only way you can define new attributes at run time is to generate new code at runtime (using Reflection.Emit, for example). But you cannot change the attributes of existing code.
You can put Boolean variable in the class to disable/enable the property instead of disabling it at run time.
You might want to look at this http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/5b0d356d-d006-43ff-bfcd-aa90dd8de6db
And Dave Morton's explanation on this blog http://blog.codinglight.com/2008/10/changing-attribute-parameters-at.html
Sounds like you want to consider implementing IXmlSerializable
You can implement IDataErrorInfo, then check range in Validate method.
public string this[string property] {
get { return Validate(property); }
}
public string Error { get; }
protected virtual string Validate(string property) {
var propertyInfo = this.GetType().GetProperty(property);
var results = new List<ValidationResult>();
var result = Validator.TryValidateProperty(
propertyInfo.GetValue(this, null),
new ValidationContext(this, null, null) {
MemberName = property
},
results);
if (!result) {
var validationResult = results.First();
return validationResult.ErrorMessage;
}
return string.Empty;
}
In sub class
protected override string Validate(string property) {
Debug.WriteLine(property);
if (property == nameof(YourProperty)) {
if (_property > 5) {
return "_property out of range";
}
}
return base.Validate(property);
}

Can anonymous class implement interface?

Is it possible to have an anonymous type implement an interface?
I've got a piece of code that I would like to work, but don't know how to do this.
I've had a couple of answers that either say no, or create a class that implements the interface construct new instances of that. This isn't really ideal, but I'm wondering if there is a mechanism to create a thin dynamic class on top of an interface which would make this simple.
public interface DummyInterface
{
string A { get; }
string B { get; }
}
public class DummySource
{
public string A { get; set; }
public string C { get; set; }
public string D { get; set; }
}
public class Test
{
public void WillThisWork()
{
var source = new DummySource[0];
var values = from value in source
select new
{
A = value.A,
B = value.C + "_" + value.D
};
DoSomethingWithDummyInterface(values);
}
public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
{
foreach (var value in values)
{
Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
}
}
}
I've found an article Dynamic interface wrapping that describes one approach. Is this the best way of doing this?
No, anonymous types cannot implement an interface. From the C# programming guide:
Anonymous types are class types that consist of one or more public read-only properties. No other kinds of class members such as methods or events are allowed. An anonymous type cannot be cast to any interface or type except for object.
While the answers in the thread are all true enough, I cannot resist the urge to tell you that it in fact is possible to have an anonymous class implement an interface, even though it takes a bit of creative cheating to get there.
Back in 2008 I was writing a custom LINQ provider for my then employer, and at one point I needed to be able to tell "my" anonymous classes from other anonymous ones, which meant having them implement an interface that I could use to type check them. The way we solved it was by using aspects (we used PostSharp), to add the interface implementation directly in the IL. So, in fact, letting anonymous classes implement interfaces is doable, you just need to bend the rules slightly to get there.
Casting anonymous types to interfaces has been something I've wanted for a while but unfortunately the current implementation forces you to have an implementation of that interface.
The best solution around it is having some type of dynamic proxy that creates the implementation for you. Using the excellent LinFu project you can replace
select new
{
A = value.A,
B = value.C + "_" + value.D
};
with
select new DynamicObject(new
{
A = value.A,
B = value.C + "_" + value.D
}).CreateDuck<DummyInterface>();
Anonymous types can implement interfaces via a dynamic proxy.
I wrote an extension method on GitHub and a blog post http://wblo.gs/feE to support this scenario.
The method can be used like this:
class Program
{
static void Main(string[] args)
{
var developer = new { Name = "Jason Bowers" };
PrintDeveloperName(developer.DuckCast<IDeveloper>());
Console.ReadKey();
}
private static void PrintDeveloperName(IDeveloper developer)
{
Console.WriteLine(developer.Name);
}
}
public interface IDeveloper
{
string Name { get; }
}
No; an anonymous type can't be made to do anything except have a few properties. You will need to create your own type. I didn't read the linked article in depth, but it looks like it uses Reflection.Emit to create new types on the fly; but if you limit discussion to things within C# itself you can't do what you want.
The best solution is just not to use anonymous classes.
public class Test
{
class DummyInterfaceImplementor : IDummyInterface
{
public string A { get; set; }
public string B { get; set; }
}
public void WillThisWork()
{
var source = new DummySource[0];
var values = from value in source
select new DummyInterfaceImplementor()
{
A = value.A,
B = value.C + "_" + value.D
};
DoSomethingWithDummyInterface(values.Cast<IDummyInterface>());
}
public void DoSomethingWithDummyInterface(IEnumerable<IDummyInterface> values)
{
foreach (var value in values)
{
Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
}
}
}
Note that you need to cast the result of the query to the type of the interface. There might be a better way to do it, but I couldn't find it.
The answer to the question specifically asked is no. But have you been looking at mocking frameworks? I use MOQ but there's millions of them out there and they allow you to implement/stub (partially or fully) interfaces in-line. Eg.
public void ThisWillWork()
{
var source = new DummySource[0];
var mock = new Mock<DummyInterface>();
mock.SetupProperty(m => m.A, source.Select(s => s.A));
mock.SetupProperty(m => m.B, source.Select(s => s.C + "_" + s.D));
DoSomethingWithDummyInterface(mock.Object);
}
Another option is to create a single, concrete implementing class that takes lambdas in the constructor.
public interface DummyInterface
{
string A { get; }
string B { get; }
}
// "Generic" implementing class
public class Dummy : DummyInterface
{
private readonly Func<string> _getA;
private readonly Func<string> _getB;
public Dummy(Func<string> getA, Func<string> getB)
{
_getA = getA;
_getB = getB;
}
public string A => _getA();
public string B => _getB();
}
public class DummySource
{
public string A { get; set; }
public string C { get; set; }
public string D { get; set; }
}
public class Test
{
public void WillThisWork()
{
var source = new DummySource[0];
var values = from value in source
select new Dummy // Syntax changes slightly
(
getA: () => value.A,
getB: () => value.C + "_" + value.D
);
DoSomethingWithDummyInterface(values);
}
public void DoSomethingWithDummyInterface(IEnumerable<DummyInterface> values)
{
foreach (var value in values)
{
Console.WriteLine("A = '{0}', B = '{1}'", value.A, value.B);
}
}
}
If all you are ever going to do is convert DummySource to DummyInterface, then it would be simpler to just have one class that takes a DummySource in the constructor and implements the interface.
But, if you need to convert many types to DummyInterface, this is much less boiler plate.
Using Roslyn, you can dynamically create a class which inherits from an interface (or abstract class).
I use the following to create concrete classes from abstract classes.
In this example, AAnimal is an abstract class.
var personClass = typeof(AAnimal).CreateSubclass("Person");
Then you can instantiate some objects:
var person1 = Activator.CreateInstance(personClass);
var person2 = Activator.CreateInstance(personClass);
Without a doubt this won't work for every case, but it should be enough to get you started:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Publisher
{
public static class Extensions
{
public static Type CreateSubclass(this Type baseType, string newClassName, string newNamespace = "Magic")
{
//todo: handle ref, out etc.
var concreteMethods = baseType
.GetMethods()
.Where(method => method.IsAbstract)
.Select(method =>
{
var parameters = method
.GetParameters()
.Select(param => $"{param.ParameterType.FullName} {param.Name}")
.ToString(", ");
var returnTypeStr = method.ReturnParameter.ParameterType.Name;
if (returnTypeStr.Equals("Void")) returnTypeStr = "void";
var methodString = #$"
public override {returnTypeStr} {method.Name}({parameters})
{{
Console.WriteLine(""{newNamespace}.{newClassName}.{method.Name}() was called"");
}}";
return methodString.Trim();
})
.ToList();
var concreteMethodsString = concreteMethods
.ToString(Environment.NewLine + Environment.NewLine);
var classCode = #$"
using System;
namespace {newNamespace}
{{
public class {newClassName}: {baseType.FullName}
{{
public {newClassName}()
{{
}}
{concreteMethodsString}
}}
}}
".Trim();
classCode = FormatUsingRoslyn(classCode);
/*
var assemblies = new[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(baseType.Assembly.Location),
};
*/
var assemblies = AppDomain
.CurrentDomain
.GetAssemblies()
.Where(a => !string.IsNullOrEmpty(a.Location))
.Select(a => MetadataReference.CreateFromFile(a.Location))
.ToArray();
var syntaxTree = CSharpSyntaxTree.ParseText(classCode);
var compilation = CSharpCompilation
.Create(newNamespace)
.AddSyntaxTrees(syntaxTree)
.AddReferences(assemblies)
.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
//compilation.Emit($"C:\\Temp\\{newNamespace}.dll");
if (result.Success)
{
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
var newTypeFullName = $"{newNamespace}.{newClassName}";
var type = assembly.GetType(newTypeFullName);
return type;
}
else
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
return null;
}
}
}
public static string ToString(this IEnumerable<string> list, string separator)
{
string result = string.Join(separator, list);
return result;
}
public static string FormatUsingRoslyn(string csCode)
{
var tree = CSharpSyntaxTree.ParseText(csCode);
var root = tree.GetRoot().NormalizeWhitespace();
var result = root.ToFullString();
return result;
}
}
}

Categories

Resources