Get AdditionalValues from containerType's instance - c#

I have something like that:
[ViewTerms]
public class Foo
{
[Term]
public string Name { get; set; }
}
my ViewTermAttribute sets some additional values in ModelMetaData:
public class ViewTermsAttribute : Attribute, IMetadataAware
{
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["values"] = someValues;
}
}
and what I need is to get this info from my 'Name' property:
public class TermAttribute : Attribute, IMetadataAware
{
public void OnMetadataCreated(ModelMetadata metadata)
{
containerAdditionalValues = //need to get here;
}
}
Is possible to get values from instance of the container?

Related

C# how to get Generic type properties

I am working on .NET 6.0 application. I have class which takes generic dictionary as parameter
Dictionary<string, TPolicyDictionary> dataPolicyDictionary
where TPolicyDictionary is class. Now this class has properties that I need to access but unable to recognise since I am expecting property definition to resolve at run time i.e. IsRequire is one of the property of class DataReadingRule that I am trying to pass generic method.
public class DataReadingRule
{
public Guid DataReadingRuleId { get; set; }
public bool IsRequire { get; set; }
}
generic class
public class IsRequiredPolicy : BaseConversionValidator, IIsRequiredPolicy
{
public IsRequiredPolicy() { }
public string Text { get; set; }
public string FieldName { get; set; }
public override Task<dynamic> Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary)
{
try
{
bool isRecordExist = false;
bool isRequired = false;
bool isRecordValid = false;
if (!string.IsNullOrWhiteSpace(FieldName))
{
var policy = dataPolicyDictionary.Where(_ => _.Key == FieldName).Select(x => x.Value).FirstOrDefault();
if (policy.IsRequire) //IsRequire doesn't recognise here
{
isRequired = true;
}
error
The property is not accessible because it is possible to pass instance of any type.
In your case you know that you pass instance of DataReadingRule but it is also possible to pass instance of object type and it does not have IsRequire property - what should compiler do it that case?
If you always know that type DataReadingRule is passed to Validate() method then you don't need this method to be generic one (if you can change signature in base class):
public override Task<dynamic> Validate(Dictionary<string, DataReadingRule> dataPolicyDictionary) { // ...}
or you can use constraint (if you can change signature in base class):
public override Task<dynamic> Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary) where TPolicyDictionary : DataReadingRule { // ...}
If you can't change signature in base class you should check the type of the policy and cast:
public override Task<dynamic> Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary)
{
try
{
bool isRecordExist = false;
bool isRequired = false;
bool isRecordValid = false;
if (!string.IsNullOrWhiteSpace(FieldName))
{
var policy = dataPolicyDictionary.Where(_ => _.Key == FieldName).Select(x => x.Value).FirstOrDefault();
if (policy is DataReadingRule dataReadingRule)
{
// property is now accessible
if (dataReadingRule.IsRequire)
{
isRequired = true;
}
// ...
}
else
{
// policy is not DataReadingRule
}
}
// ...
}
}
Or if you can create interface:
public interface IRule
{
public bool IsRequire { get; } // add setter if needed
}
Then implement it:
public class DataReadingRule : IRule
{
public Guid DataReadingRuleId { get; set; }
public bool IsRequire { get; set; }
}
And then add constraint (in base class) and your method will be:
public override Task<dynamic> Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary)
where TPolicyDictionary : IRule // constraint
{
// your code without changes
}
Carry on #Roman suggestion
Put common properties in Base class and extend the classes from it
public class BaseDataRule
{
public bool IsRequire { get; set; }
}
In Abstract class
public abstract ValidationStatus Validate<TPolicyDictionary>(Dictionary<string, TPolicyDictionary> dataPolicyDictionary) where TPolicyDictionary : BaseDataRule;

Downcasting a List<AbstractClass> object to what the object actually is

I have a ParentClass. Two classes are inherit from it, FirstChildClass and SecondChildClass. A class MultipleValueTypes contains a Dictionary and a method that adds values to it. My intention is to be able to pass values of different classes, which inherit from the same abstract class to the value parameter of the Dictionary. Therefore, I initialize the dictionary with the value List<ParentClass> so that I would be able to add objects made with the child classes to the Dictionary. I can do this, but I cannot access them, therefore in the abstract class I create a way to tell them apart, a virtual method that both the children classes override to return their own class type.
I test the values they return against the enum itself and based on whether the condition is fulfilled, the object would be casted as what it is instead of a List<ParentClass>. Is this the wrong approach? Is this impossible?
I think it should work, because in my thinking the FirstObject and SecondObject are still objects of their respective classes, so casting should work and I should be able to access the overridden method.
What doesn't work: I cannot access the method that returns what type of class it is, because it only gets methods from the List<ParentClass>.
What I've tried so far: searching for a way to access the method, but I did not find any.
What I still need help with: everything mentioned above.
public abstract class ParentClass
{
public string Name { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
}
public class FirstChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public FirstChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the FirstChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
private string _randomvalue;
public string RandomValue { get => _randomvalue; set => _randomvalue = value; }
public SecondChildClass(string Name) : base(Name)
{
}
public void ReturnMessage()
{
Console.WriteLine("This is the SecondChildClass");
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public Dictionary<string, List<ParentClass>> ADictionary = new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if (!ADictionary.ContainsKey(Name))
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
class Program
{
static void Main(string[] args)
{
FirstChildClass FirstObject = new FirstChildClass("FirstObject");
SecondChildClass SecondObject = new SecondChildClass("SecondObject");
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if(TestDictionary.ADictionary["FirstObject"].TypeOfClass() == ParentClass.ChildClasses.FirstChildClass) ///List<ParentClass>' does not contain a definition for 'TypeOfClass' and no accessible extension method 'TypeOfClass' accepting a first argument of type 'List<ParentClass>' could be found (are you missing a using directive or an assembly reference?)
{
TestDictionary.ADictionary["FirstObject"] = (FirstChildClass)TestDictionary.ADictionary["FirstObject"]; ///Cannot convert type 'System.Collections.Generic.List<Dictionary.ParentClass>' to 'Dictionary.FirstChildClass
}
}
}
You forgot to use indexer of the list value of the key of the dictionary here:
==> TestDictionary.ADictionary["FirstObject"][0]
Here is your code now refactored too:
class Program
{
static void Main(string[] args)
{
var FirstObject = new FirstChildClass("FirstObject");
var SecondObject = new SecondChildClass("SecondObject");
FirstObject.ReturnMessage();
SecondObject.ReturnMessage();
MultipleValueTypes TestDictionary = new MultipleValueTypes();
TestDictionary.AddObject("FirstObject", FirstObject);
TestDictionary.AddObject("SecondObject", SecondObject);
if ( TestDictionary.ADictionary["FirstObject"][0].TypeOfClass()
== ParentClass.ChildClasses.FirstChildClass )
{
TestDictionary.ADictionary["FirstObject"][0]
= (FirstChildClass)TestDictionary.ADictionary["FirstObject"][0];
}
Console.ReadKey();
}
}
public abstract class ParentClass
{
public string Name { get; set; }
public string RandomValue { get; set; }
public ParentClass(string Name)
{
this.Name = Name;
}
public virtual void ReturnMessage()
{
Console.WriteLine($"This is the {this.GetType().Name} instance");
}
public virtual ChildClasses TypeOfClass()
{
return ChildClasses.NoChildClass;
}
public enum ChildClasses
{
NoChildClass = 0,
FirstChildClass = 1,
SecondChildClass = 2
}
}
public class FirstChildClass : ParentClass
{
public FirstChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.FirstChildClass;
}
}
public class SecondChildClass : ParentClass
{
public SecondChildClass(string Name)
: base(Name)
{
}
public override ChildClasses TypeOfClass()
{
return ChildClasses.SecondChildClass;
}
}
class MultipleValueTypes
{
public readonly Dictionary<string, List<ParentClass>> ADictionary
= new Dictionary<string, List<ParentClass>>();
public void AddObject(string Name, ParentClass variable)
{
if ( !ADictionary.ContainsKey(Name) )
{
ADictionary.Add(Name, new List<ParentClass>());
}
ADictionary[Name].Add(variable);
}
}
If the intention is to cast the whole list from List<ParentClass> to List<FirstChildClass> and List<SecondChildClass>, then Linq is your friend, just use the Cast function:
List<FirstChildClass> firstChildClasses = TestDictionary.ADictionary["FirstObject"]
.Cast<FirstChildClass>().ToList();
List<SecondChildClass> secondChildClasses = TestDictionary.ADictionary["SecondObject"]
.Cast<SecondChildClass>().ToList();

Access const with generics C#

I have the following base class:
public class Base
{
public string LogicalName { get; set; }
public int NumberOfChars { get; set; }
public Base()
{
}
public Base(string logicalName, int numberOfChars)
{
LogicalName = logicalName;
NumberOfChars = numberOfChars;
}
}
and the following derived classes:
public class Derived1 : Base
{
public const string EntityLogicalName = "Name1";
public const int EntityNumberOfChars = 30;
public Derived1() : base(EntityLogicalName, EntityNumberOfChars)
{
}
}
public class Derived2 : Base
{
public const string EntityLogicalName = "Name2";
public const int EntityNumberOfChars = 50;
public Derived2()
: base(EntityLogicalName, EntityNumberOfChars)
{
}
}
and I also have this function that is provided by a service:
public IEnumerable<T> GetEntities<T>(string entityName, int numberOfChars) where T : Base
{
//Some code to get the entities
}
My problem is how can I call this function generically? I want to call it with something that looks like this:
public void TestEntities<T>() where T : Base
{
var entities = GetEntities<T>(T.EntityLogicalName, T.EntityNumberOfChars);
//some other code to test the entities
}
This of course doesn't work because at this point T is not known. How can I accomplish something similar to this? EntityLogicalName and EntityNumberOfChars are characteristics that all Base derived classes have and they never change for each derived class. Can I get them from the Base class without instantiating objects or some other way that I am not seeing?
Replace constants with getter abstract properties
public abstract class Base
{
public abstract string LogicalName { get; }
public abstract int NumberOfChars { get; }
public Base()
{
}
}
public class Derived1 : Base
{
public string LogicalName { get { return "Name1"; } }
public int NumberOfChars { get { return 30; } }
public Derived1() : base()
{
}
}
Also, you will be able to put some logic into overriden getter, e.g. :
...
public string LogicalName { get { return this.EntityMap.Name; } }
...
UPDATE: The fact that you do not want to instantiate object from class but want to be able to get that string in a strongly typed manner can be handled in one more way. It is totally separate from answer above ( Since you can't override static props in c#). Consider the following code. We are adding one more class here, but LocatorInner can be a member of BaseClass. We are using this approach a lot in several existing apps.:
public class Locator
{
public static class LocatorInner<T> where T : BaseClass
{
public static string Name { get; set; }
}
public static string GetName<T>() where T : BaseClass
{
return LocatorInner<T>.Name;
}
public static void SetName<T>(string name) where T : BaseClass
{
LocatorInner<T>.Name = name;
}
}
public class BaseClass
{
}
public class DerivedClass: BaseClass
{
static DerivedClass()
{
Locator.LocatorInner<DerivedClass>.Name = "me";
}
}
public class TestClass<T> where T : BaseClass
{
public void Method()
{
var name = Locator.GetName<T>();
}
}
IMHO, I believe using constants here is a bad design decision.
You can either solve the issue using #vittore approach, but for me it sounds like you should use meta-programming with attributes if you're looking to get data from the T generic argument
For example, what about:
public class LogicalNameAttribute : Attribute
{
public LogicalNameAttribute(string name)
{
Name = name;
}
public string Name { get; private set; }
}
public class NumberOfCharsAttribute : Attribute
{
public NumberOfCharsAttribute (int number)
{
Number = number;
}
public string Number { get; private set; }
}
[LogicalName("Name1"), NumberOfChars(30)]
public class Derived1 : Base
{
public Derived1() : base()
{
}
}
Now your service method can extract attribute metadata as follows:
public void TestEntities<T>() where T : Base
{
LogicalNameAttribute logicalNameAttr = typeof(T).GetCustomAttribute<LogicalNameAttribute>();
NumberOfCharsAttribute numberOfCharsAttr = typeof(T).GetCustomAttribute<NumberOfCharsAttribute >();
Contract.Assert(logicalNameAttr != null);
Contract.Assert(numberOfCharsAttr != null);
string logicalName = logicalNameAttr.Name;
int numberOfChars = numberOfCharsAttr.Number;
// Other stuff
}
There's a performance penalty because you need to use reflection to get attributes applied to T, but you gain the flexibility of not forcing derived classes to provide this static info.
As #vittore mentioned, move the properties to base,pass the hard coded values from derived and in creation use just defautl(T)
public IEnumerable<T> GetEntities<T>(string entityName, int numberOfChars) where T : Base
{
yield return default(T); //Is its always class use new constraint and return new T();
}

Instantiating a class given a generic abstract type

Using this model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
#region Abstracts definitions
abstract class AnAbstract
{
public string Name { get { return this.GetType().Name; } }
public bool IsNumeric { get { return this is ANumericAbstract; } }
public /*abstract*/ string Description = default(string);
}
abstract class ANumericAbstract : AnAbstract
{
public /*abstract*/ double Min = double.MinValue;
public /*abstract*/ double Max = double.MaxValue;
}
abstract class ANonNumericAbstract : AnAbstract
{
public List<Object> objects = new List<Object>();
}
#endregion Abstracts definitions
#region Concrete definitions
class NumericImpl : ANumericAbstract
{
new public const string Description = "A numeric implementation";
new public const double Min = 0;
new public const double Max = 1000;
public NumericImpl()
{
}
}
abstract class AnotherImpl : ANonNumericAbstract
{
public AnotherImpl()
{
objects.Add("one");
objects.Add("two");
objects.Add("three");
}
}
class SideA : AnotherImpl
{
new public const string Description = "Disc side A";
}
class SideB : AnotherImpl
{
new public const string Description = "Disc side B";
}
#endregion Concrete definitions
partial class Parameter
{
public string Name { get; set; }
public string Description { get; set; }
public bool IsNumeric { get; private set; }
public double Min { get; private set; }
public double Max { get; private set; }
public List<Object> Values { get; private set; }
private Parameter()
{
Values = new List<Object>();
}
}
}
With this, I pretend to define a hierarchy of classes for which I can have some abstract properties (Name,Description,IsNumeric) and at the end of the hierarchy there should be some classes which mandatorily define those properties; in the case of ANumericAbstract they should have additional specific properties, e.g. Min and Max.
Now here's the problem.
I'm attemtping to be able to create instances of Parameter which take a generic AnAbstract and read from it some values to fill in the Parameter properties, à la
Parameter<ANumericAbstract> ParamNum = new Parameter<NumericImpl>();
where a Parameter constructor would take in the passed type and "fill in the blanks". In other words, I'm trying something like:
using System;
namespace ConsoleApplication1 {
partial class Parameter
{
public static Parameter NewParameter<T>() where T : AnAbstract
{
Parameter Parameter = new Parameter();
// THESE DON'T WORK:
this.Name = T.Name;
this.Description = T.Description;
this.IsNumeric = T.IsNumeric;
if (this.IsNumeric)
{
this.Min = (T as ANumericAbstract).Min;
this.Max = (T as ANumericAbstract).Max;
}
else
{
foreach(Object val in (T as ANonNumericAbstract).Values)
{
this.Values.Add(val);
}
}
return Parameter;
}
}
class Program
{
private AnAbstract Number = new NumericImpl();
static void Main(string[] args)
{
}
// THESE DON'T WORK:
private static Parameter<ANumericAbstract> ParameterNum =
Parameter.NewParameter<NumericImpl>();
private static Parameter<ANonNumericAbstract> ParameterA =
Parameter.NewParameter<SideA>();
private static Parameter<ANonNumericAbstract> ParameterB =
Parameter.NewParameter<SideB>();
}
}
Obviously the syntax is invalid, but I'm not sure if I'm going in the right direction. Is there some Generics syntax that I'm not using properly? Should I just be done with it and use Getters and Setters à la Java? :-) At this point, just doing the
Parameter par = new Parameter { Name = NumericImpl.Name, /* ... */ };
might seem more sensible...
Firstly you should not use New keyword on your properties.
Consider virtual keyword:
abstract class AnAbstract
{
public virtual string Name { get { return this.GetType().Name; } }
public virtual string Description { get { return String.Empty; } }
}
abstract class ANumericAbstract : AnAbstract
{
public virtual double Min = double.MinValue;
}
class NumericImpl : ANumericAbstract
{
public override string Description { get { return "A numeric implementation"; } }
public override double Min { get { return 0; } }
}
1) You can place an instance of you type in Parameter constructor and have Parameter instance.
partial class Parameter
{
public Parameter(AnAbstract inputObject)
{
this.Name = inputObject.Name;
// etc
}
}
private static Parameter ParameterNum = new Parameter(new NumericImpl());
2) The second way is to use reflection to create an instance of object with initial parameters.
partial class Parameter<T> where T : AnAbstract
{
public static Parameter<T> NewParameter<T>() where T : AnAbstract
{
Parameter<T> parameter = new Parameter<T>();
AnAbstract instance = (AnAbstract)Activator.CreateInstance(typeof(T));
parameter.Name = instance.Name;
// etc
return parameter;
}
}
private static Parameter<NumericImpl> ParameterNum =
Parameter<NumericImpl>.NewParameter();
3) Make Parameter class static and create in via static constructor.
static partial class Parameter<T> where T : AnAbstract
{
public static string Name { get; set; }
//etc
}
static partial class Parameter<T> where T : AnAbstract
{
static Parameter ()
{
AnAbstract instance = (AnAbstract)Activator.CreateInstance(typeof(T));
Parameter<T>.Name = instance.Name;
//etc
}
}
In the last example you can use this class like this:
String someName = Parameter<NumericImpl>.Name;

MEF Import Scenario

Hi
I have some problems in import scenarios example:
[Export(typeof(IICon))]
public class WriteInputData : IICon
{
[Import(typeof(IIOWriter))]
public IIOWriter IOWriter { get; set; }
public object Input { get; set; }
public void Process()
{
IOWriter.Write(Input);
}
}
Then i hawe two classes that implement interface IIOWriter like :
[Export(typeof(IIOWriter))]
public class FileWriter : IIOWriter
{
public string FilePath { get; set; }
public void Write(object data)
{
if (string.IsNullOrEmpty(FilePath))
FilePath = #"c:\test.txt";
var fl = new StreamWriter(FilePath, true);
fl.Write((string)data);
fl.Flush();
fl.Close();
}
public string Name
{
get { return "FileWriter"; }
}
}
[Export(typeof(IIOWriter))]
public class ConsoleWrite : IIOWriter
{
public void Write(object data)
{
Console.WriteLine((string)data);
}
public string Name
{
get { return "ConsoleWrite"; }
}
}
How can i let that to user so he can change that in runtime, so example whene he type select in ListBox FileWriter than the IIOWriter in WriteInputData will be injected FileWriter end so one..
Sorry for my bad english.
You probably need to supply some metadata to the export, such like:
[Export(typeof(IIOWriter)),
ExportMetadata("Name", "ConsoleWriter")]
public class ConsoleWriter : IIOWriter
{
}
The reason you need to do this, is that you need to know ahead of time what the user selection will match to. Because of this, you may want to refactor your design to remove the dependency on the IOWriter property:
[Export(typeof(IICon))]
public class WriteInputData : IICon
{
public object Input { get; set; }
public void Process(IIOWriter writer)
{
}
}
If you define your Process method to take in an instance, we can resolve it using the CompositionContainer. Firstly, define a metadata interface that matches your ExportMetadata value:
public interface INamedMetadata
{
string Name { get; }
}
And then, we can resolve the instance:
public IIOWriter GetWriter(string name)
{
return container
.GetExports<IIOWriter, INamedMetadata>()
.Where(e => e.Metadata.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
.Select(e => e.Value)
.FirstOrDefault();
}
Hope that points you in the right direction....

Categories