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);
Related
I have a lot of duplicate code places:
if (claimSettingHistoryDto.NewClaimTypeName == claimSettingHistoryDto.OldClaimTypeName)
{
claimSettingHistoryDto.NewClaimTypeName = null;
claimSettingHistoryDto.OldClaimTypeName = null;
}
if (claimSettingHistoryDto.NewApplicantName == claimSettingHistoryDto.OldApplicantName)
{
claimSettingHistoryDto.NewApplicantName = null;
claimSettingHistoryDto.OldApplicantName = null;
}
if (claimSettingHistoryDto.NewDamageSparePartsTotalCostInsertion == claimSettingHistoryDto.OldDamageSparePartsTotalCostInsertion)
{
claimSettingHistoryDto.NewDamageSparePartsTotalCostInsertion = null;
claimSettingHistoryDto.OldDamageSparePartsTotalCostInsertion = null;
}
and so constantly for different classes of different fields
I wish I had a feature like this:
private void SetNull(object newData, object oldData)
{
if (newData == oldData)
{
newData = null;
oldData = null;
}
}
but of course I understand that this is not true, since I only change the local value inside the function. How do I change the class field?
There are multiple ways of doing that, with varying positions on the "good idea" to "bad idea" spectrum.
Fields as ref parameters (good idea)
(...) this is not true, since I only change the local value inside the function
You're wrong, because ref and out parameters allow you to change values non-locally.
If you have access to the actual fields, you can pass them as a ref parameter:
public class Dto
{
private string? _old;
private string? _new;
public string? Old => _old;
public string? New => _new;
public void Foo() {
SetNullIfEqual(ref _new, ref _old);
}
private static void SetNullIfEqual<T>(ref T? newData, ref T? oldData) where T: class
{
if (newData == oldData)
{
newData = null;
oldData = null;
}
}
}
More info on passing as reference here.
This won't work with properties, even if they have a default setter. Properties are not fields, they're methods in disguise. If you can't access the actual fields...
Properties as delegates (meh idea)
... having access to properties only you'd need to pass them as delegates like this:
public class Dto
{
public string? Old { get; set; }
public string? New { get; set; }
}
public class Outside
{
public void Foo(Dto dto) {
SetNullIfEqual(() => dto.New, () => dto.Old, v => dto.New = v, v => dto.Old = v);
}
private static void SetNullIfEqual<T>(
Func<T?> getNew,
Func<T?> getOld,
Action<T?> setNew,
Action<T?> setOld) where T: class
{
if (getNew() == getOld())
{
setNew(null);
setOld(null);
}
}
}
This is clunky though, you have to question how much space it'd actually save. An instance method working on fields as in the first suggestion works much better.
When you have reflection everything looks like a nail (probably bad idea)
You can also do this with reflection, which will remove all safety, give much worse performance, but the absolute most flexibility.
using System.Reflection;
public class Dto
{
public string? Old { get; set; }
public string? New { get; set; }
}
public class Outside
{
public void Foo(Dto dto) {
SetNullIfEqual(nameof(dto.New), nameof(dto.Old), dto);
}
private static void SetNullIfEqual<T>(
string newPropName,
string oldPropName,
T instance)
{
PropertyInfo newProp = typeof(T).GetProperty(newPropName);
PropertyInfo oldProp = typeof(T).GetProperty(oldPropName);
if (Equals(newProp.GetValue(instance), oldProp.GetValue(instance)))
{
newProp.SetValue(instance, null);
oldProp.SetValue(instance, null);
}
}
}
I removed all error handling for brevity.
Recommendation
I'd go with the fields-as-ref-parameters way. If the method in question lives outside of the type, so it can't have access to the fields (don't ever use public fields please), I'd just move it into the type. In your case it'd be a bunch of methods called SetClaimTypeName, SetApplicantName, etc.
I'm struggling migrating from protobuf-net v2.4.6 to v3.0.100 (or any 3.0.x) in regards to an existing type hierarchy used as ProtoContracts with one of the subtypes requiring a surrogate due to one of its property being of type object.
With previous configuration in place, I get the following exception thrown on creating the runtime model:
System.InvalidOperationException: 'Types with surrogates cannot be used in inheritance hierarchies'
Hence, my question is how to properly deal with this scenario using protobuf-net 3.0.x?
Here's my (over-)simplified repro of the issue:
class Program
{
static void Main(string[] args)
{
var model = RuntimeTypeModel.Create();
_ = model[typeof(Base)]; // <-- InvalidOperationException thrown here
Base value = new Complex();
var copy = model.DeepClone(value);
}
}
[ProtoContract]
[ProtoInclude(1, typeof(Simple))]
[ProtoInclude(2, typeof(Complex))]
public abstract class Base
{
}
[ProtoContract]
public class Simple : Base
{
}
[ProtoContract(Surrogate = typeof(ComplexSurrogate))]
public class Complex : Base
{
}
[ProtoContract(Name = nameof(Complex))]
public class ComplexSurrogate
{
[ProtoConverter]
public static ComplexSurrogate Convert(Complex source) => new ComplexSurrogate();
[ProtoConverter]
public static Complex Convert(ComplexSurrogate source) => new Complex();
}
As a side note: When compiling protobuf-net from source with the above mentioned exception suppressed, I'm able to defined a surrogate for the Base class which seems to serve as a workaround.
Right now, that scenario isn't supported. While reworking the code for v3, some ambiguous outcomes/intents were found, and it needs work to go in and figure out what the correct outcomes are in each case, design how to achieve that, implement it, and test it. That time has not yet been found, so right now it is safer to prevent a configuration that could lead to big problems downstream, than to just shrug and assume that whatever happens is correct. It is on my list of things to do, but: ultimately this is a project that comes entirely out of my own spare time - it isn't sponsored or part of my paid work, so: it'll get there when it gets there.
I encountered the same error in protobuf v3, and I solved that with custom serializer.
My base class is
[ProtoContract]
[ProtoInclude(500, typeof(XXXRequest))]
[ProtoInclude(501, typeof(XXXResponse))]
// ...
public class MessageBase
{
[ProtoMember(1)]
long ID { get; internal set; }
[ProtoMember(3)]
int ExecutionMilliseconds { get; set; }
}
Its equivalent proto is
message Message {
int64 ID = 1;
int32 ExecutionMilliseconds = 3;
oneof body {
PredictBonusRequest XXXRequest = 500;
PredictBonusResponse XXXResponse = 501;
// ...
}
}
I want to replace some types (e.g. XXXResponse) to use the contract-first class instead. This would allow us to migrate from code-first to contract-first smoothly.
For sub-types should be surrogated, we create custom serializer as below.
using ProtoBuf;
using ProtoBuf.Serializers;
using UnderlyingMessage = GeneratedProto.Contract.Message;
using UnderlyingResponse = GeneratedProto.Contract.XXXResponse;
[DataContract]
[Serializable]
[ProtoContract(Serializer = typeof(XXXResponseSerializer))]
public class XXXResponse : MessageBase
{
class XXXResponseSerializer : ISerializer<XXXResponse>
{
public SerializerFeatures Features => SerializerFeatures.CategoryMessage | SerializerFeatures.WireTypeString;
public XXXResponse Read(ref ProtoReader.State state, XXXResponse value)
{
ISerializer<UnderlyingMessage> serializer = state.GetSerializer<UnderlyingMessage>();
return serializer.Read(ref state, value);
}
public void Write(ref ProtoWriter.State state, XXXResponse value)
{
ISerializer<UnderlyingMessage> serializer = state.GetSerializer<UnderlyingMessage>();
serializer.Write(ref state, value);
}
}
private readonly UnderlyingResponse _resp;
public XXXResponse() : this(new UnderlyingResponse() { })
{
}
private XXXResponse(UnderlyingResponse msg)
{
_resp = msg;
}
public static implicit operator XXXResponse(UnderlyingMessage value)
{
if( value != null)
{
return new XXXResponse(value.XXXResponse)
{
ID = value.ID,
ExecutionMilliseconds = value.ExecutionMilliseconds,
};
}
return null;
}
public static implicit operator UnderlyingMessage(XXXResponse value)
{
if(value != null)
{
return new UnderlyingMessage()
{
ID = value.ID,
ExecutionMilliseconds = value.ExecutionMilliseconds,
XXXResponse = value._resp,
};
}
return null;
}
public Transaction[] Transactions
{
get { return _resp.Transactions?.Select(t => (Transaction)t)?.ToArray(); }
set { _resp.Transactions = value?.Select(t => (BE.Data.Contract.Transaction)t)?.ToList(); }
}
public long DomainID { get { return _resp.DomainID; } set { _resp.DomainID = value; } }
public string UniversalID { get { return _resp.UniversalID; } set { _resp.UniversalID = value; } }
public string ExtraData { get { return _resp.ExtraData; } set { _resp.ExtraData = value; } }
// other proxied fields ...
}
The key is, when ISerializer.Read or ISerializer.Write is fired, the wire-format is from the scope of the entrie message, including all fields of base class, and current sub-type is in a field whose number is identified by ProtoInclude.
In our case this works. For other sub-types which we don't want surrogate at this moment, it still works as it did.
I'm trying to convert a collection of model objects that share a common parent, into one of DTOs. Likewise, I want to reverse the procedure - taking a collection of DTOs with a common parent into one of model objects.
From what I've read, a Factory Pattern seems to be what I'm looking for. I also have a Producer class that handles the conversion between object model and DTO by calling the relevant factory method.
There are a few limitations:
This is an open source library, and I don't want to add methods to existing classes. Otherwise a visitor pattern would have worked. Please correct me if I'm wrong.
Similarly, I don't want to add any additional packages to this project. From what I understand, AutoMapper would have been one of the ways to go about this.
I'm new(ish) to C# and design patterns, so I apologize if I am doing something that doesn't make sense.
Here is some sample code representing what I've tried so far. I used some references from online to get an idea, but something about it doesn't seem right. There was another way mentioned here: Is a switch statement applicable in a factory method? c#, but I'm not sure if that is transferrable to this scenario.
Any critique or suggestions is welcome.
Example Usage
Animal pet1 = new Pigeon("Pidgey", 100, false);
Animal pet2 = new Rattlesnake("Ekans", 20.0, true);
IList<Animal> myPets = new List<Animal>() { pet1, pet2 };
AnimalDTOProducer dtoProducer = new AnimalDTOProducer(new AnimalDTOFactory());
IList<AnimalDTO> myDTOs = new List<AnimalDTO>();
myDTOs = dtoProducer.ConvertAnimalCollection(myPets);
Models
public abstract class Animal
{
public Animal(string name)
{
Name = name;
}
public string Name { get; set; }
// business logic
}
public abstract class Bird : Animal
{
public Bird(string name, int maxAltitude, bool isReal)
: base(name)
{
Name = name;
MaxAltitude = maxAltitude;
IsReal = isReal;
}
public int MaxAltitude { get; set; }
public bool IsReal { get; set; }
// business logic
}
public class Pigeon : Bird
{
public Pigeon(string name, int maxAltitude, bool isReal)
: base(name, maxAltitude, isReal)
{
}
// business logic
}
public abstract class Snake : Animal
{
public Snake(string name, double length, bool isPoisonous)
: base(name)
{
Name = name;
Length = length;
IsPoisonous = isPoisonous;
}
public double Length { get; set; }
public bool IsPoisonous { get; set; }
// business logic
}
public class Rattlesnake : Snake
{
public Rattlesnake(string name, double length, bool isPoisonous)
: base(name, length, isPoisonous)
{
}
// business logic
}
DTOs
public abstract class AnimalDTO { }
public class PigeonDTO : AnimalDTO
{
public string Name { get; set; }
public int MaxAltitude { get; set; }
public bool IsReal { get; set; }
}
public class RattlesnakeDTO : AnimalDTO
{
public string Name { get; set; }
public double Length { get; set; }
public bool IsPoisonous { get; set; }
}
Factories
public interface IFactory { }
public interface IAnimalFactory : IFactory
{
Animal CreateAnimal(AnimalDTO DTO);
}
public interface IAnimalDTOFactory : IFactory
{
AnimalDTO CreateAnimalDTO(Animal animal);
}
public class AnimalFactory : IAnimalFactory
{
public Animal CreateAnimal(AnimalDTO DTO)
{
switch (DTO)
{
case PigeonDTO _:
var pigeonDTO = (PigeonDTO)DTO;
return new Pigeon(pigeonDTO.Name, pigeonDTO.MaxAltitude, pigeonDTO.IsReal);
case RattlesnakeDTO _:
var rattlesnakeDTO = (RattlesnakeDTO)DTO;
return new Rattlesnake(rattlesnakeDTO.Name, rattlesnakeDTO.Length, rattlesnakeDTO.IsPoisonous);
// And many more ...
default:
return null;
}
}
}
public class AnimalDTOFactory : IAnimalDTOFactory
{
public AnimalDTO CreateAnimalDTO(Animal animal)
{
switch (animal)
{
case Pigeon _:
var _pigeon = (Pigeon)animal;
return new PigeonDTO()
{
Name = _pigeon.Name,
MaxAltitude = _pigeon.MaxAltitude,
IsReal = _pigeon.IsReal
};
case Rattlesnake _:
var _rattlesnake = (Rattlesnake)animal;
return new RattlesnakeDTO()
{
Name = _rattlesnake.Name,
Length = _rattlesnake.Length,
IsPoisonous = _rattlesnake.IsPoisonous
};
// And many more ...
default:
return null;
}
}
}
Producers
public interface IProducer { }
public interface IAnimalProducer : IProducer
{
Animal ProduceAnimalFromDTO(AnimalDTO DTO);
}
public interface IAnimalDTOProducer : IProducer
{
AnimalDTO ProduceAnimalDTOFromAnimal(Animal animal);
}
public class AnimalProducer : IAnimalProducer
{
private IAnimalFactory factory;
public AnimalProducer(IAnimalFactory factory)
{
this.factory = factory;
}
public IList<Animal> ConvertAnimalDTOCollection(IList<AnimalDTO> DTOCollection)
{
IList<Animal> result = new List<Animal>();
foreach (AnimalDTO DTO in DTOCollection)
{
var dto = ProduceAnimalFromDTO(DTO);
if (dto != null)
result.Add(dto);
}
return result;
}
public Animal ProduceAnimalFromDTO(AnimalDTO animalDTO)
{
return this.factory.CreateAnimal(animalDTO);
}
}
public class AnimalDTOProducer : IAnimalDTOProducer
{
private IAnimalDTOFactory factory;
public AnimalDTOProducer(IAnimalDTOFactory factory)
{
this.factory = factory;
}
public IList<AnimalDTO> ConvertAnimalCollection(IList<Animal> collection)
{
IList<AnimalDTO> result = new List<AnimalDTO>();
foreach (Animal animal in collection)
{
var _animal = ProduceAnimalDTOFromAnimal(animal);
if (_animal != null)
result.Add(_animal);
}
return result;
}
public AnimalDTO ProduceAnimalDTOFromAnimal(Animal animal)
{
return this.factory.CreateAnimalDTO(animal);
}
}
UPDATE 1
As recommended by sjb-sjb and ChiefTwoPencils in the comments, I eliminated the switch statements from the respective factories. The result looks like this:
public class AnimalFactory : IAnimalFactory
{
public Animal CreateAnimal(AnimalDTO DTO)
{
Type srcType = DTO.GetType();
Type modelType = Type.GetType(Regex.Replace(srcType.FullName, #"(DTO)$", ""));
IList<PropertyInfo> props = new List<PropertyInfo>(srcType.GetProperties());
var propVals = props.Select(prop => prop.GetValue(DTO, null)).ToArray();
Animal animal = (Animal)Activator.CreateInstance(modelType, propVals);
return animal;
}
}
public class AnimalDTOFactory : IAnimalDTOFactory
{
public AnimalDTO CreateAnimalDTO(Animal animal)
{
Type srcType = animal.GetType();
Type dtoType = Type.GetType($"{srcType.FullName}DTO");
AnimalDTO dto = (AnimalDTO)Activator.CreateInstance(dtoType, new object[] { });
foreach (PropertyInfo dtoProperty in dtoType.GetProperties())
{
PropertyInfo srcProperty = srcType.GetProperty(dtoProperty.Name);
if (srcProperty != null)
{
dtoProperty.SetValue(dto, srcProperty.GetValue(animal));
}
}
return dto;
}
}
The one thing I forgot to mention in the original question was that the constructor for the model may have more arguments than the DTO object has properties. That, and the order of arguments may not be the same. I think in pseudo-code, a solution will look something like this:
void AssignParamsToConstructor()
{
// Extract constructer parameters with names into an ordered list
// Match DTO properties with extracted parameters via name and type
// Fill any missing parameters with a default value or null
// Pass the final list of parameters as an array to Activator.CreateInstance method
}
I will be researching on a way to resolve this for the time being, but any pointers will be welcome.
UPDATE 2
Okay, so I found a kind of hacky solution for the previous problem regarding calling the Model constructor with missing or out-of-order arguments.
I created a helper class that creates an ordered argument array based on a combination of the Model constructor arguments and the DTO properties. This array can then be passed to Activator.CreateInstance without causing any issues.
Here is the updated AnimalFactory.CreateAnimal method:
public Animal CreateAnimal(AnimalDTO DTO)
{
Type srcType = DTO.GetType();
Type modelType = Type.GetType(Regex.Replace(srcType.FullName, #"(DTO)$", ""));
object[] propVals = Helpers.GenerateConstructorArgumentValueArray(modelType, DTO);
Animal animal = (Animal)Activator.CreateInstance(modelType, propVals);
return animal;
}
And here is the helper class:
public static class Helpers
{
public static object[] GenerateConstructorArgumentValueArray(Type type, object obj)
{
IList<(string, Type)> ctorArgTypes = new List<(string, Type)>();
IList<(string, object)> propVals = new List<(string, object)>();
// Get constructor arguments
ctorArgTypes = GetConstructorArgumentsAndTypes(type);
// Get object properties
propVals = GetObjectPropertiesAndValues(obj);
// Create args array
IList<object> paramVals = new List<object>();
foreach (var ctorArg in ctorArgTypes)
{
object val;
string _name = ctorArg.Item1.ToLower();
(string, object) _namedProp = propVals.Where(prop => prop.Item1.ToLower() == _name).FirstOrDefault();
if (_namedProp.Item2 != null)
{
val = _namedProp.Item2;
}
else
{
val = ctorArg.Item2.IsValueType ? Activator.CreateInstance(ctorArg.Item2) : null;
}
paramVals.Add(val);
}
return paramVals.ToArray();
}
private static IList<(string, Type)> GetConstructorArgumentsAndTypes(Type type)
{
List<(string, Type)> ctorArgs = new List<(string, Type)>();
TypeInfo typeInfo = type.GetTypeInfo();
ConstructorInfo[] ctors = typeInfo.DeclaredConstructors.ToArray();
ParameterInfo[] ctorParams = ctors[0].GetParameters();
foreach (ParameterInfo info in ctorParams)
{
ctorArgs.Add((info.Name, info.ParameterType));
}
return ctorArgs;
}
private static IList<(string, object)> GetObjectPropertiesAndValues(object obj)
{
List<(string, object)> props = new List<(string, object)>();
PropertyInfo[] propInfo = obj.GetType().GetProperties();
foreach (PropertyInfo info in propInfo)
{
string name = info.Name;
object val = info.GetValue(obj);
props.Add((name, val));
}
return props;
}
}
I'll have to look at this later to see how it can be improved on. For the time being however, it does its job.
I would appreciate any comments or input if you have any. I will keep updating this post until I find an absolute solution.
So I worked out a solution that seems to achieve my original goal.
The reason it was difficult to solve at first was due to the original Factory class having too many responsibilities. It had to map the properties and create a new object. Separating these made it easy to implement the Generic Factory suggested by this post:
https://web.archive.org/web/20140414013728/http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c
I created a simple mapper that would automatically map Entity and DTO properties. The easier solution is to use an AutoMapper like grandaCoder suggested. My situation required otherwise so a custom mapper was the way to go. I also tried to minimize calls to System.Reflection so the performance wouldn't suffer too much.
The end result is a Factory that can convert between any Entity and DTO object, maps properties between them, and can instantiate an Entity class with no default / empty constructor.
I ended up making a lot more changes to the original post, so I uploaded the end result to github: https://github.com/MoMods/EntityDTOFactory
I am open to any additional ideas / criticisms on the final solution. This is my first time solving this kind of problem, so it's very likely there are some better ideas out there.
Thanks again for the help and suggestions!
The switch statement can be avoided using reflection:
public AnimalDTO ToDTO( Animal src)
{
Type srcType = src.GetType();
Type dtoType = Type.GetType(srcType.Name + "DTO");
AnimalDTO dto = (AnimalDTO)Activator.CreateInstance(dtoType, new object[] { });
foreach (PropertyInfo dtoProperty in dtoType.GetProperties()) {
PropertyInfo srcProperty = srcType.GetProperty(dtoProperty.Name);
if (srcProperty != null) {
dtoProperty.SetValue(dto, srcProperty.GetValue(src));
}
}
return dto;
}
To get a FromDTO method, just reverse the roles of src and dto in ToDTO.
I would not reinvent the wheel on this common scenario.
https://automapper.org/
https://www.nuget.org/packages/automapper/
OR
https://github.com/MapsterMapper/Mapster
https://www.nuget.org/packages/Mapster/
.......
Learn how to use one of these frameworks.
Below is mapster..........."performance" numbers.......which is how I found it (someone told me to lookout for automapper performance)
Very new to C# so forgive me if this is a silly question.
If I have a base class called Validator, and a number of classes which inherit from this class such as validateFirstname, validateSecondname etc... is it possible to write a method which will loop through each of these subclasses and instantiate each?
Something along the lines of
public class loadValidators
{
public loadValidators()
{
foreach (subclass in class)
{
// instantiate class here
}
}
}
Any help is much appreciated as always.
Try this:
var validator_type = typeof (Validator);
var sub_validator_types =
validator_type
.Assembly
.DefinedTypes
.Where(x => validator_type.IsAssignableFrom(x) && x != validator_type)
.ToList();
foreach (var sub_validator_type in sub_validator_types)
{
Validator sub_validator = (Validator)Activator.CreateInstance(sub_validator_type);
}
This code assumes that all the sub classes live in the same assembly/project as the Validator class.
Also, it assumes that each of the subclasses have a public parameterless constructor.
Please note that I would not recommend this approach.
Instead you should do something like this to solve your problem (of modeling/using multiple validators):
public interface IValidator
{
bool Validate(SomeObject something);
}
public class FirstNameValidator : IValidator
{
public bool Validate(SomeObject something)
{
...
}
}
public class LastNameValidator : IValidator
{
public bool Validate(SomeObject something)
{
...
}
}
public class CompositeValidator : IValidator
{
private readonly IValidator[] m_Validators;
public CompositeValidator(params IValidator[] validators)
{
m_Validators = validators;
}
public bool Validate(SomeObject something)
{
foreach (IValidator validator in m_Validators)
{
if (!validator.Validate(something))
return false;
}
return true;
}
}
The CompositeValidator wraps multiple validators and knows how to validate objects using those validators.
You can use it like this:
var composite_validator = new CompositeValidator(new FirstNameValidator() , new LastNameValidator());
composite_validator.Validate(obj);
I need a base class with a property where I can derive classes with the same property but different (compatible) types. The base Class can be abstract.
public class Base
{
public virtual object prop { get; set; }
}
public class StrBase : Base
{
public override string prop { get; set; } // compiler error
}
public class UseIt
{
public void use()
{
List<Base> l = new List<Base>();
//...
}
}
I tried it with Generics but that gives me a problem when using the class, because I want to store differently typed base classes in the List.
public class BaseG<T>
{
public T prop { get; set; }
}
public class UseIt
{
public void use()
{
List<BaseG> l = new List<BaseG>(); // requires type argument
//...
}
}
Here's an alternative approach to proposed solution:
public abstract class Base
{
public abstract void Use();
public abstract object GetProp();
}
public abstract class GenericBase<T> : Base
{
public T Prop { get; set; }
public override object GetProp()
{
return Prop;
}
}
public class StrBase : GenericBase<string>
{
public override void Use()
{
Console.WriteLine("Using string: {0}", Prop);
}
}
public class IntBase : GenericBase<int>
{
public override void Use()
{
Console.WriteLine("Using int: {0}", Prop);
}
}
Basically I've added a generic class in the middle that stores your properly-typed property. this will work assuming that you never need to access Prop from the code that iterates the members of the List<Base>. (You could always add an abstract method to Base called GetProp that casts the generic to an object if that's required.)
Sample usage:
class Program
{
static void Main(string[] args)
{
List<Base> l = new List<Base>();
l.Add(new StrBase {Prop = "foo"});
l.Add(new IntBase {Prop = 42});
Console.WriteLine("Using each item");
foreach (var o in l)
{
o.Use();
}
Console.WriteLine("Done");
Console.ReadKey();
}
}
Edit: Added the GetProp() method to illustrate how the property can be directly accessed from the base class.
You can't override the type of a property. Take a look at the following code:
StrBase s = new StrBase();
Base b = s;
This is completely valid code. But what happens when you try to do this?
b.prop = 5;
The integer can be converted to object, because everything is derived from object. But since b is actually a StrBase instance, it would have to convert the integer to a string somehow, which it can't. So that is why you aren't allowed to override the type.
The same principle applies to generics:
List<BaseG<object>> l = new List<BaseG<object>>();
BaseG<string> s = new BaseG<string>();
// The compiler will not allow this.
l.add(s);
// Here's the same problem, convert integer to string?
BaseG<object> o = l[0];
o.prop = 5;
This is because generic types in C# 2.0 are invariant. C# 4.0 does allow this type of conversions, called covariance and contravariance.
Solutions
An option is to cast the object back to string when you need it. You could add type validation in the subclass:
public class StrBase : Base
{
private string propValue;
public override object prop {
get
{
return this.propValue;
}
set
{
if (value is string)
{
this.propValue = (string)value;
}
}
}
}
You could also expose a type-safe property in the subclass:
public class StrBase : Base
{
public string strProp {
get
{
return (string)this.prop;
}
set
{
this.prop = value;
}
}
}
This is possible since C# 9.0
Beginning with C# 9.0, override methods support covariant return types.
(see Microsoft docs)
public class First
{
private int someV;
public virtual object SomeV { get => someV; set => someV = (int)value; }
public First() { }
}
public class Two : First
{
private string someV;
public override object SomeV { get => someV; set => someV = value.ToString(); }
public Two() { }
}
and use of those:
First firstClass = new First();
firstClass.SomeV = 1;
Two twoClass = new Two();
twoClass.SomeV = "abcd";