C#: GetCustomAttribute returns different instance? [duplicate] - c#

This question already has answers here:
.NET Attributes: Why does GetCustomAttributes() make a new attribute instance every time?
(3 answers)
Closed 2 years ago.
Shouldn't PropertyInfo.GetCustomAttribute(s) return the same instance of Attribute? The following code appears it returns different instances:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Reflection;
namespace AttributeNoShared
{
[TestClass]
public class UnitTest1
{
private sealed class AnyAttribute : Attribute
{
}
private sealed class AnyClass
{
[Any]
public int AnyProperty { get; set; }
}
[TestMethod]
public void TestMethod1()
{
var propertyInfo = typeof(AnyClass).GetProperty(nameof(AnyClass.AnyProperty));
var result1 = propertyInfo.GetCustomAttribute<AnyAttribute>();
var result2 = propertyInfo.GetCustomAttribute<AnyAttribute>();
Assert.AreEqual(result1, result2); // This succeeded
Assert.IsTrue(object.ReferenceEquals(result1, result2), "Different instance of attribute"); // This failed
}
}
}
Is this a bug? I'm expecting runtime Attribute to be shared because I would like to store some state in it.

No, it's not an error, that's by dessign. Attributes aren't instanced until they are requested. In order to return the same instance .net would need to create a cache for the attributes and that could lead to consume too much memory in some scenerios as these would need to be preserve during all the life of the process.
Anyways, you can always create static properties that are shared by all the instances. If you thought that there would be one instance of the attribute per each tagged property you can do something like this:
public class InformationAttribute : Attribute
{
static Dictionary<string, object> storage = new Dictionary<string, object>();
string propName;
public InformationAttribute(string PropertyName)
{
propName = PropertyName;
}
public void SetValue(object Value)
{
storage[propName] = Value;
}
public object GetValue()
{
if(storage.ContainsKey(propName))
return storage[propName];
return null;
}
}
and use like this:
private sealed class AnyClass
{
[Information("AnyClass.AnyProperty")]
public int AnyProperty { get; set; }
}
//...
var propertyInfo = typeof(AnyClass).GetProperty(nameof(AnyClass.AnyProperty));
var result = propertyInfo.GetCustomAttribute<AnyAttribute>();
if(result.GetValue() == null)
result.SetValue(WhatEverYouWantToStore);

Related

Generic class and method binding with delegates(or not) for clean method expression

Lets say you have simple chained method but you are trying to access or set a value in a class property (internal/external doesnt matter). Using a Func seems to be working and finds the relation between generic class that is passed and access its properties correctly but i am not sure if its necessary.
Is there a way of setting the method variable cleanly as in Main method below since it is aware of the Generic class association without doing new Props().Property for example?
//sample console app
public class Props {
public string FirstProp = "lets say object";
public string SecondProp = "Pretend some other object";
}
public class Logic<T> where T : class, new()
{
private string outString { get; set; }
public Logic<T> GetPropertyValue(Func<T, object> propertySelector)
{
return this;
}
public Logic<T> GetLambda(Expression<Func<T, object>> propertySelector)
{
var breakpointCheck = propertySelector; //{x => x.SecondProp}
return this;
}
}
class Program
{
static void Main(string[] args)
{
var Test =
new Logic<Props>()
.GetPropertyValue(x => x.FirstProp) //dummy check
.GetLambda(x => x.SecondProp); //passed correctly {x => x.SecondProp}
var HowToGetThis =
new Logic<Props>()
.GetPropertyValue(FirstProp) // or GetPropertyValue(Props.FirstProp)
.GetLambda(x => x.SecondProp);
}
}

How to use Bogus Faker with initialization properties?

I have an immutable DTO that I'd like to fake with Bogus Faker (version 31.0.2) but the property with an overriding rule only returns what it was initialized with by the constructor:
Example DTO (real ones are more complex)
using Xunit;
using Bogus;
namespace SO.Tests
{
class ClassWithInitialization
{
public ClassWithInitialization(string name)
{
this.Name = name
}
public string Name { get; }
}
Example DTO Faker
class FakeClassWithInitialization : Faker<ClassWithInitialization>
{
private FakeClassWithInitialization() { }
public static CreateDefault()
{
return (FakeClassWithInitialization) new FakeClassWithInitialization()
.CustomInstantiator(f => new ClassWithInitialization(null))
.RuleFor(o => o.Name, f => f.Person.FullName);
}
public FakeClassWithInitialization WithName(string name)
{
RuleFor(o => o.Name, f => name);
return this;
}
}
Example Tests
Both of the following tests fail as the Name property remains null as provided in the constructor.
public class Tests
{
[Fact]
public void TestClassWithInitialization()
{
var faker = FakeClassWithInitialization
.CreateDefault();
var testPoco = faker.Generate();
Assert.False(string.IsNullOrEmpty(testPoco.Name)); #fails
}
[Fact]
public void TestClassWithInitialization_with_overriding_rule()
{
var faker = FakeClassWithInitialization
.CreateDefault()
.WithName("John Smith");
var testPoco = faker.Generate();
Assert.AreEqual("John Smith", testPoco.Name); #fails
}
}
}
Although I could use Faker to generate random data for the constructor I would like to be able to use this fake instance to generate alternative versions, for instance, with a fixed Name as exampled by the second test above.
Why is this not working and are there any known workarounds?
Note: this is not the same as the question How can I use Bogus with private setters
It is possible but I'd advise against it because the solution relies on .NET's Reflection.
There's a new Faker<T>(binder:...) binder constructor parameter. The IBinder interface is what Faker<T> uses to reflect over T to discover properties and fields that are settable. Whatever IBinder.GetMembers(Type t) returns is what Faker<> sees in T.
With this information, let's look at how the compiler generates an object with a public parameterized constructor and read-only property:
public class Foo
{
public Foo(string name){
this.Name = name;
}
public string Name { get; }
}
The C# compiler generates:
public class Foo
{
// Fields
[CompilerGenerated, DebuggerBrowsable((DebuggerBrowsableState) DebuggerBrowsableState.Never)]
private readonly string <Name>k__BackingField;
// Methods
public Foo(string name)
{
this.<Name>k__BackingField = name;
}
// Properties
public string Name => this.<Name>k__BackingField;
}
The storage for the Foo.Name property uses a backing field called Foo.<Name>k__BackingField. This backing field is what we need IBinder to hoist into Faker<>. The following BackingFieldBinder : IBinder does this:
public class BackingFieldBinder : IBinder
{
public Dictionary<string, MemberInfo> GetMembers(Type t)
{
var availableFieldsForFakerT = new Dictionary<string, MemberInfo>();
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;
var allMembers = t.GetMembers(bindingFlags);
var allBackingFields = allMembers
.OfType<FieldInfo>()
.Where(fi => fi.IsPrivate && fi.IsInitOnly)
.Where(fi => fi.Name.EndsWith("__BackingField"))
.ToList();
foreach( var backingField in allBackingFields){
var fieldName = backingField.Name.Substring(1).Replace(">k__BackingField","");
availableFieldsForFakerT.Add(fieldName, backingField);
}
return availableFieldsForFakerT;
}
}
Customize the GetMembers() method above to suit your needs. You'll need to change the code if you want to include public fields or properties of T too.
The last problem we have to solve is creating an object without specifying constructor arguments. We can do this by using .GetUninitializedObject() from FormatterServices or RuntimeHelpers. To do this, we'll create an extension method that extends the Faker<T> API as shown below:
public static class MyExtensionsForFakerT
{
public static Faker<T> SkipConstructor<T>(this Faker<T> fakerOfT) where T : class
{
return fakerOfT.CustomInstantiator( _ => FormatterServices.GetUninitializedObject(typeof(T)) as T);
}
}
With these two components in place, we can finally write the following code:
void Main()
{
var backingFieldBinder = new BackingFieldBinder();
var fooFaker = new Faker<Foo>(binder: backingFieldBinder)
.SkipConstructor()
.RuleFor(f => f.Name, f => f.Name.FullName());
var foo = fooFaker.Generate();
foo.Dump();
}
public class Foo
{
public Foo(string name)
{
this.Name = name;
}
public string Name {get;}
}
You can find a full working example here. Additionally, you may find other solutions in Issue 213 helpful.
I just tried this and it seems to work :
class FakeClassWithInitialization : Faker<ClassWithInitialization>
{
private FakeClassWithInitialization() { }
public static FakeClassWithInitialization CreateDefault()
{
return (FakeClassWithInitialization) new FakeClassWithInitialization()
.CustomInstantiator(f => new ClassWithInitialization(f.Person.FullName));
}
}
I used directly the class constructor with the generator instead of using the generator with the property.
I also remove the WithName method that was not used.
Edit : Seems I misunderstood the question.
I don't know much about Bogus. I thought you could use optional parameters in "CreateDefault" method but you told DTO was complex so... There will be too much parameters.
I think you can achieve what you want with the builder pattern :
public class Builder
{
private string _name;
public Builder WithName(string name)
{
_name = name;
return this;
}
public ClassWithInitialization Build()
{
return new Faker<ClassWithInitialization>()
.CustomInstantiator(f =>
new ClassWithInitialization(
_name ?? f.Person.FullName
))
.Generate();
}
}
var faker = new Builder().WithName("Hello").Build();
var faker2 = new Builder().Build();
You can delete the FakeClassWithInitialization and replace it with a classic "Builder".

Reflection only successful on first call in Blazor-State-Management

I discovered a weird behavior where I absolutely don't know where it comes from or how to fix it.
The issue arises with the blazor-state management (which is based on the mediator pattern) - library can be found here: https://timewarpengineering.github.io/blazor-state/.
Lets assume we have the following base class for an enumeration:
public abstract class Simple<TSimple> where TSimple: Simple<TSimple>
{
private readonly string _key;
protected Simple(string key)
{
_key = key;
}
public virtual string Key => _key;
public static TSimple Create(string key)
{
var obj = All.SingleOrDefault(e => e.Key == key);
return obj;
}
public static IReadOnlyCollection<TSimple> All => GetAll();
private static IReadOnlyCollection<TSimple> GetAll()
{
var enumerationType = typeof(TSimple);
return enumerationType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(info => enumerationType.IsAssignableFrom(info.FieldType))
.Select(info => info.GetValue(null))
.Cast<TSimple>()
.ToArray();
}
}
And the following enumeration implementation:
public class SimpleImpl : Simple<SimpleImpl>
{
public static readonly SimpleImpl One = new SimpleImpl("Important");
public static readonly SimpleImpl Two = new SimpleImpl("Urgent");
public static readonly SimpleImpl Three = new SimpleImpl("ImportantAndUrgent");
public static readonly SimpleImpl Four = new SimpleImpl("None");
private SimpleImpl(string key) : base(key)
{
}
}
So far so good.
I use this enumeration in a blazor app, where the data is retrieved via gRPC-Web from the backend, is transformed and added to the state.
So the code section of the Index.cshtml looks something like this:
#code
{
private AppState AppState => GetState<AppState>();
protected override async Task OnInitializedAsync()
{
foreach (var simple in new[] {"Important", "Urgent", "ImportantAndUrgent", "None"})
{
await Mediator.Send(new AppState.AddAction(simple));
}
}
This gets handled by the Handler:
public partial class AppState
{
public class AppHandler : ActionHandler<AddAction>
{
private AppState AppState => Store.GetState<AppState>();
public AppHandler(IStore store) : base(store)
{
}
public override async Task<Unit> Handle(AddAction aAction, CancellationToken aCancellationToken)
{
var simple = SimpleImpl.Create(aAction.Simple);
Console.WriteLine(simple == null); // First call false, afterwards true
AppState.Simples.Add(simple); // If I don't add the object to the state, Simple.Create always returns an object
return await Unit.Task;
}
}
}
And here is the problem. On the first try everything works, but if the functions gets called a second time (so my gRPC-Client returns multiple items) simple will always be null. If I remove the AppState.Simples.Add(simple) then it works again.
If I add the following code: Console.WriteLine(string.Join(",", SimpleImpl.All.Select(s => s.Key)); on the first run it prints all the possible values:
Important,Urgent,ImportantAndUrgent,None
On the second run, this:
,Urgent,,
Urgent was in the Dto in the first run. So it seems something to do with how the reference in the List is kept alive (which should not interfer with how the reflection part in Simple works).
Furthermore: in the GetAll() function of Simple everything works fine until the Select(info => .GetValue(null)) The FieldInfo-Property itself holds all 4 options. After GetValue and the cast there is only the last choosen one "alive".
The State-Entity looks like the following:
public partial class AppState : State<AppState>
{
public IList<SimpleImpl> Simples { get; private set; }
public override void Initialize()
{
Simples = new List<SimpleImpl>();
}
}
And the Action of this sample:
public partial class AppState
{
public class AddAction : IAction
{
public AddAction(string simple)
{
Simple = simple;
}
public string Simple { get; }
}
}
This code is running under .NET Core 3.1.
If anybody has a tip where the problem lays I would be very thankful.
Thanks to #steven-t-cramer how helped me on finding the issue.
Basically it all boils down to the Mediator.Send and State-Handling.
In the Blazor-State library a clone is created when one dispatches and handles an action (so you as a developer don't have to take care of that). But exactly this cloning messed up big time here because of the static nature of Simple(basically an enumeration class).
To get around that, the state can implement ICloneable and do this stuff on its own.
A very naive way to do would be that:
public partial class AppState : State<AppState>, ICloneable
{
private List<SimpleImpl> _simples = new List<SimpleImpl>();
public IReadOnlyList<SimpleImpl> Simples => _simples.AsReadOnly();
public override void Initialize()
{
_simples = new List<SimpleImpl>();
}
public object Clone()
{
var state = new AppState { _simples = _simples};
return state;
}
}

Concise way of deserializing json to an interface?

I have a config service which wraps the baked-in assembly settings, but I'd also like to override these on the command line.
Currently this code is working fine:
public interface ISettings
{
string Url { get; }
}
public class OperationalSettings : ISettings
{
public string Url { get { return ServiceSettings.Default.Url; } }
}
public class CommandLineModel
{
public string Url;
}
public class CommandLineSettings : ISettings
{
private readonly CommandLineModel _model;
public CommandLineSettings(string serialisedSettings)
{
_model = JsonConvert.DeserializeObject<CommandLineModel>(serialisedSettings);
}
public string Url { get { return _model.Url; } }
}
public class ConfigService
{
private readonly ISettings _settings;
public ConfigService(ISettings settings)
{
_settings = settings;
}
public ISettings settings { get { return _settings; } }
}
Then the test driver code:
class Program
{
static void Main(string[] args)
{
ISettings opSettings = new OperationalSettings();
var commandLineTest = "{Url:'http://overridenurl.com'}";
ISettings commandSettings = new CommandLineSettings(commandLineTest);
var configService = new ConfigService(opSettings);
var configServiceUsingCmdOpts = new ConfigService(commandSettings);
}
}
So with this I can override settings using the command line string. However, what I don't like is that if I have a new settings, I now need to add this in 4 places:
The interface
The concrete implementation of the settings wrapper (OperationalSettings)
The command line model for deserialisation
The command line settings implementation that wraps the deserialised model.
This seems to suffer from scalability once I add more properties. Is there a more efficient way to achieve this without so many code changes?
You might take a look at DynamicObject
public class CommandLineModelDictionary : DynamicObject
{
// The inner dictionary.
Dictionary<string, object> dictionary
= new Dictionary<string, object>();
// This property returns the number of elements
// in the inner dictionary.
public int Count
{
get
{
return dictionary.Count;
}
}
// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
}
Otherwise If you have a simple scenario in which you need an object that can only add and remove members at run time but that does not need to define specific operations and does not have static members, use the ExpandoObject class
here how to use
class Program
{
public static dynamic Dyn { get; set; }
static void Main(string[] args)
{
dynamic model= new CommandLineModelDictionary();
model.Prop1 = "Foo";
model.Prop2 = "toto";
Console.WriteLine(model.Prop1);
Console.WriteLine(model.Prop2);
//otherwise you can use
dynamic dynModel = new ExpandoObject();
dynModelop1 = "Test1";
dynModel2 = "Test2";
Console.WriteLine(dynModel.Prop1);
Console.WriteLine(dynModel.Prop2);
}
}

Reflecting Over Nested Instances without Creating New Instance

I have been struggling a bit with some reflection code that I though would be simple. Essentially, I have an interface that defines a method. Then, I have an abstract class that provides a base implementation of that method.
The concrete classes can contain nested instances of other classes that can also derive from the same base class. It can be illustrated by the following sample:
using System.Linq;
public interface ISampleObject
{
bool IsValid();
}
public abstract class SampleObjectBase : ISampleObject
{
public bool IsValid()
{
var returnValue = true;
// Self-validation sets the return value.
var childProperties = this.GetType().GetProperties().Where(pi => typeof(ISampleObject).IsAssignableFrom(pi.PropertyType));
foreach (var childProperty in childProperties)
{
// var childInstance = ????; // Need the actual *existing* instance property, cast to ISampleObject.
// if (childInstance.IsValid() != true)
// {
// returnValue = false;
// }
}
return returnValue;
}
}
public sealed class InnerSampleObject : SampleObjectBase
{
}
public sealed class OuterSampleObject : SampleObjectBase
{
public InnerSampleObject DerivedSampleObject { get; set; }
}
My problem is that in the commented code for SampleObjectBase, I cannot get the concrete instance of the matching PropertyInfo value. If I look at the PropertyInfo object in the loop, I see that the type is correct, but I cannot find a way to directly access the instance that already exists in the implementation. So, when executing, for example, OuterSampleObject.IsValid(), the code finds the PropertyInfo for InnerSampleObject, as expected. I want to execute InnerSampleObject.IsValid().
I have tried (multiple variations of):
var childIsValid = (bool)contractProperty.PropertyType.InvokeMember("IsValid", BindingFlags.InvokeMethod, null, null, null);
And:
var childInstance = (ISampleContract)contractProperty;
The problem with the first one is that I can't pass null in as the target for InvokeMember, as IsValid() is not static (nor can it be, since I am focused on the actual instance). The second on is just a lame cast, but is the gist of what I want to accomplish.
The sample code above is just a minimalist example of what I want to achieve. The full code is part of a self-validating DTO that recursively checks the entire hierarchy and returns what children have validation issues and what they are.
Any help would be greatly appreciated.
How about:
var instance = childProperty.GetValue(this, null) as ISampleObject;
if (instance != null)
{
if (!instance.IsValid())
return false;
}
Please see if the code below is what you are looking for. My changes are marked with a comment starting with //VH:
public interface ISampleObject
{
bool IsValid();
}
public abstract class SampleObjectBase : ISampleObject
{
public virtual bool IsValid()
{
var returnValue = true; //VH: Changed value from false to true
// Self-validation sets the return value.
var childProperties = this.GetType().GetProperties().Where(pi => typeof(ISampleObject).IsAssignableFrom(pi.PropertyType));
foreach (var childProperty in childProperties)
{
//VH: Here is how you get the value of the property
var childInstance = (ISampleObject)childProperty.GetValue(this, null);
if (childInstance.IsValid() != true)
{
returnValue = false;
}
}
return returnValue;
}
}
public sealed class InnerSampleObject : SampleObjectBase
{
}
public sealed class OuterSampleObject : SampleObjectBase
{
//VH: Added this constructor
public OuterSampleObject()
{
DerivedSampleObject = new InnerSampleObject();
}
public InnerSampleObject DerivedSampleObject { get; set; }
}
class Program
{
static void Main(string[] args)
{
OuterSampleObject c = new OuterSampleObject();
c.IsValid();
}
}
Just use
var childInstance = (ISampleObject)childProperty.GetValue(this, null);

Categories