I'm reading some code, can you please explain what the below line does?
bool isFeatureEnabled = FeatureControl.Current.Features.AppDesigner.IsEnabled(organizationId,currentOrgDBVersion);
Here's the definitions of the above code
public sealed class FeatureControl : IFeatureControl
{
public static IFeatureControl Current { get; }
[XmlIgnore]
public IFeatureDetailContainer Features { get; set; }
....
}
public interface IFeatureControl
{
IFeatureDetailContainer Features { get; set; }
...
}
public interface IFeatureDetailContainer
{
IFeatureDetail AppDesigner { get; }
}
public interface IFeatureDetail
{
bool IsEnabled(Guid organizationId, Version currentOrgDBVersion);
}
I don't see any instances created, how does this work?
Sorry, I copied metadata, I just found the actual code:
public sealed class FeatureControl : IFeatureControl
{
private static readonly Lazy<IFeatureControl> current = new Lazy<IFeatureControl>(() => new FeatureControl());
private IFeatureDetailContainer features;
public static IFeatureControl Current
{
get
{
return current.Value;
}
}
/// <summary>
/// Accessor to the Features List for Developers to retrieve the information
/// </summary>
[XmlIgnore]
public IFeatureDetailContainer Features
{
get
{
return this.features;
}
set
{
this.features = value;
}
}
}
It is a singleton pattern. Normally, the instance is created inside constructor.
public interface IFeatureControl { }
public sealed class FeatureControl : IFeatureControl
{
public static IFeatureControl Current { get; }
static FeatureControl()
{
if (Current == null)
{
Current = new FeatureControl();
}
}
}
[TestFixture]
public class FeatureControlTests
{
[Test]
public void IsFeatureControlSingleton()
{
IFeatureControl c1 = FeatureControl.Current;
IFeatureControl c2 = FeatureControl.Current;
Assert.AreSame(c1, c2);
}
}
At some point in the code (not shown here) you can expect the object IFeatureControl::Current is being created / new'd.
Your line of code is merely accessing that value. Note that if you run the code without actually instantiating the Current object you'll get a null ref. error.
You can program an elaborate set of code using Interfaces and the code will compile and look great, however if none of the interface objects are instantiated with new'd instances of classes that inherit from the Interface you'll get null reference exceptions.
Consider the use of interfaces in this example an outline for how things WILL be arranged and how they WILL operate. However it's just an outline and you'll need to colour inside the lines to actually achieve an outcome.
Good luck!
Related
I have two groups of classes in my code and one group has logic and other group has data and inheritance is also being used in each group. I tried to mimic the situation which I am dealing with in below code snippet. The problem I have is how to handle the objects of derived data classes efficiently in related instances of logic classes. Right now I am trying to cast the instance of derived data class in a method of derived logic class which I do not think is logical. I need some guidance to address this issue.
void Main()
{
var item1 = new D1();
var holder1 = new DataHolder1() { localProp1 = "test" };
var holderout = item1.Method1(holder1);
holderout.Dump();
}
public class BaseDataHolder
{
public string prop { get; set; }
}
public class DataHolder1 : BaseDataHolder
{
public string localProp1 { get; set; }
}
public class DataHolder2 : BaseDataHolder
{
public string localProp2 { get; set; }
}
public class BaseClass
{
public virtual BaseDataHolder Method1(BaseDataHolder holder)
{
return null;
}
}
public class D1 : BaseClass
{
public override BaseDataHolder Method1(BaseDataHolder holder)
{
(holder as DataHolder1).localProp1.Dump();
(holder as DataHolder1).localProp1 = "change1";
return holder;
}
}
public class D2 : BaseClass
{
public override BaseDataHolder Method1(BaseDataHolder holder)
{
(holder as DataHolder2).localProp2.Dump();
(holder as DataHolder2).localProp2 = "change2";
return holder;
}
}
I don't see why it would be illogical since looks like you are trying to get DataHolder1 always in class D1. Rather, why can't your class compose with Data class instance and use that in method like
public class D1 : BaseClass
{
private readonly DataHolder1 holder;
public D1(DataHolder1 holder) { this.holder = holder; }
public override BaseDataHolder Method1()
{
holder.localProp1.Dump();
holder.localProp1 = "change1";
return holder;
}
}
Then you can just say
var item1 = new D1(new DataHolder1());
BaseDataHolder data = item1.Method1();
This violates the Liskov substitution principle. In summary, it's bad, because your signature promises to work well with any BaseDataHolder but in reality it will just crash if the wrong BaseDataHolder is passed in.
I cannot really give a solution because we don't know your requirements. From what you have posted, your three logic classes should drop the inheritance and just have three different method signatures, each telling what it needs instead of all of them lying about what they need and then crashing randomly.
I am designing a system that works with multiple data sources. These data sources have identifiers that can have certain checks done on them when they are created. It permits getting historical and real time data. My current abstraction involves three base classes.
The DataSource class is responsible for connections to services and maintaining esoteric things for that data source including how to open and close connections and thread safety concerns on a case by case basis.
The DataContext class is responsible for which values to get, be they realtime or historic and on what date etc, there may be other contexts where you could desire mixed historic dates (parameterized) among other things which is why I want to use polymorphism to accomplish this.
The Identifier class is responsible for parsing strings and validation against regular expressions to make sure that the string identifier that gets passed in is at least valid to some degree. It is also used for the type safety, because an identifier for one data source is not allowed to be passed into another data source.
See example code below;
public class DataSource
{
// base class for all data sources
// maintains connections opening and closing plus
// thread safety concerns
}
public class FooDataSource : DataSource { }
public class BarDataSource : DataSource { }
public abstract class Identifier
{
public string Value { get; internal set; }
public Identifier(string value)
{
Value = value;
}
}
public class FooIdentifier : Identifier
{
public FooIdentifier(string value) : base(value)
{
// checks go here on the string that comes in
// specific to the foo data source
}
}
public class BarIdentifier : Identifier
{
public BarIdentifier(string value) : base(value)
{
// checks on the string values that come in for the Bar
// source
}
}
public abstract class DataContext<TIdentifier> where TIdentifier : Identifier
{
public abstract double GetValue(TIdentifier id);
}
public abstract class FooDataContext : DataContext<FooIdentifier> { }
public abstract class BarDataContext : DataContext<BarIdentifier> { }
public class FooRealTimeDataContext : FooDataContext
{
public override double GetValue(FooIdentifier id)
{
// real implementation here
return -1;
}
}
public class BarRealTimeDataContext : BarDataContext
{
public override double GetValue(BarIdentifier id)
{
// real implementation here
return -10;
}
}
[TestFixture]
public static class TestMe
{
[Test]
public static void MyTest()
{
// create the data context (to get data from)
var ctx = new FooRealTimeDataContext();
ctx.GetValue(new FooIdentifier("onetuhoenthuo")); // compiles (good)
// ctx.GetValue(new BarIdentifier("noetuhneoth")); // does not compile (also good)
}
}
The question (finally) is how do I create a class that actually follows OOP principals to fill in the following class shell?
public class UniversalRealTimeDataSource : DataSource<Identifier> {
public double GetValue(Identifier id) {
// there would have to be code in here that says "if(id is FooIdentifier) ... else ...
// which is (IMO) an anti-pattern so, how to avoid this?
}
}
Edit: I have been trying to keep the compile time type safety guarantees as much as possible. This would be fairly straightforward with some if(!(id is FooIdentifier)) throw exception type of code but I want to make it impossible for this to occur at compile time.
My final solution is a bit of a compromise in terms of compile time type safety. The Identifier selects its own data source from a menu of data sources (the universal data source). This prevents run-time errors unless the programmer uses the code incorrectly. Many things will probably be made private, the public layer will include all DataContext and Identifier subclasses.
public abstract class DataSource
{
// base class for all data sources
// maintains connections opening and closing plus
// thread safety concerns
// these classes will most likely be private
// maybe even within the universal data source class as inner classes
// THE TWO METHODS BELOW ARE ONLY TO BE CALLED FROM WITHIN THE UniversalDataSource CLASS
public abstract double GetRealTimeValue(Identifier id);
public abstract double GetHistoricalValue(Identifier id, DateTime asof);
}
public class FooDataSource : DataSource {
public override double GetRealTimeValue(Identifier id)
{
return -1;
// real implementation here, must be identifier type upcasting with runtime check
}
public override double GetHistoricalValue(Identifier id, DateTime asof)
{
return -2;
// real implementation here, must be identifier type upcasting with runtime check
}
}
public class BarDataSource : DataSource {
public override double GetRealTimeValue(Identifier id)
{
return -3;
// real implementation here, must be identifier type upcasting with runtime check
}
public override double GetHistoricalValue(Identifier id, DateTime asof)
{
return -4;
// real implementation here, must be identifier type upcasting with runtime check
}
}
/// <summary>
/// holds initialized references to all possible data sources
/// </summary>
public class UniversalDataSource
{
public FooDataSource FooDS { get; internal set; }
public BarDataSource BarDS { get; internal set; }
public UniversalDataSource(FooDataSource fooDs, BarDataSource barDs)
{
this.FooDS = fooDs;
this.BarDS = barDs;
}
public double GetRealTimeValue(Identifier id)
{
var specificDS = id.GetDataSource(this);
return specificDS.GetRealTimeValue(id);
}
public double GetHistoricalValue(Identifier id, DateTime asof)
{
var specificDS = id.GetDataSource(this);
return specificDS.GetHistoricalValue(id, asof);
}
}
public abstract class Identifier
{
public string Value { get; internal set; }
public Identifier(string value)
{
Value = value;
}
/// <summary>
/// returns the appropriate data source for THIS kind of identifier (abstractly)
/// </summary>
/// <param name="universalDataSource"></param>
/// <returns></returns>
public abstract DataSource GetDataSource(UniversalDataSource universalDataSource);
}
public class FooIdentifier : Identifier
{
public FooIdentifier(string value) : base(value)
{
// checks go here on the string that comes in
// specific to the foo data source
}
public override DataSource GetDataSource(UniversalDataSource universalDataSource)
{
return universalDataSource.FooDS;
}
}
public class BarIdentifier : Identifier
{
public BarIdentifier(string value) : base(value)
{
// checks on the string values that come in for the Bar
// source
}
public override DataSource GetDataSource(UniversalDataSource universalDataSource)
{
return universalDataSource.BarDS;
}
}
public abstract class DataContext
{
public UniversalDataSource DataSource { get; internal set; }
protected DataContext(UniversalDataSource dataSource)
{
DataSource = dataSource;
}
public abstract double GetValue(Identifier id);
}
public class RealTimeDataContext : DataContext {
public RealTimeDataContext(UniversalDataSource dataSource) : base(dataSource)
{
}
public override double GetValue(Identifier id)
{
return DataSource.GetRealTimeValue(id);
}
}
public class HistoricalDataContext : DataContext {
public DateTime AsOf { get; internal set; }
public HistoricalDataContext(UniversalDataSource dataSource, DateTime asof) : base(dataSource)
{
AsOf = asof;
}
public override double GetValue(Identifier id)
{
return DataSource.GetHistoricalValue(id, AsOf);
}
}
[TestFixture]
public static class TestMe
{
[Test]
public static void MyTest()
{
// create the data context (to get data from)
var ds = new UniversalDataSource(
new FooDataSource(),
new BarDataSource()
);
var realTimeDataContext = new RealTimeDataContext(ds);
var historicalDataContext = new HistoricalDataContext(ds, DateTime.MinValue);
var fooId = new FooIdentifier("onetuhoenthuo");
var barId = new BarIdentifier("onetuhoenthuo");
// testing dispatch
Assert.AreEqual(-1, realTimeDataContext.GetValue(fooId));
Assert.AreEqual(-2, historicalDataContext.GetValue(fooId));
Assert.AreEqual(-3, realTimeDataContext.GetValue(barId));
Assert.AreEqual(-4, historicalDataContext.GetValue(barId));
}
}
Perhaps this solution will clear up what I have been trying to do from the start. The reason for the data context class to even exist is due to working with financial data, weekends and holidays can cause NA values and shuffling dates for different identifiers may make sense in a historical data request setting. These strategies will be implemented polymorphically by overriding the GetValue methods.
I have been battling with this bit of code for a while now and I am trying to get a solution as it is literally the last part before it goes to testing.
I have the following interfaces and classes (simplified to the relevant parts):
public interface ITagParent<T> where T : ITag
{
List<TagAddOn<T>> TagCollection { get; set; }
}
public interface ITag
{
int Id { get; set; }
string Description { get; set; }
TagGroup TagGroup { get; set; }
}
public class TagAddOn<T> : ViewModelBase where T : ITag
{
private T _currentTag;
public T CurrentTag
{
get { return _currentTag; }
set { _currentTag = value; }
}
}
public partial class Customer : ITagParent<CustomerTag>
{
List<TagAddOn<CustomerTag>> _tagCollection;
public List<TagAddOn<CustomerTag>> TagCollection
{
get { return _tagCollection; }
set { _tagCollection = value; }
}
}
public partial class CustomerTag : ITag
{
public int Id { get; set; }
}
public class TagAddOnManager
{
public static string GetTagCurrentValue(List<TagAddOn<ITag>> dataObjectAddOns)
{
// LOTS OF SNIPPING!
return string.Empty;
}
}
I am trying to use the GetTagCurrentValue method in the TagAddOnManager class like this:
string value = TagAddOnManager.GetTagCurrentValue(
((ITagParent<ITag>)gridCell.Row.Data).TagCollection));
Everything compiles fine, but errors when trying to cast gridCell.Row.Data to ITagParent<ITag>. I understand this is due to covarience and a workaround (if not a terribly safe one) is to mark T in the ITagParent interface with the out keyword, but that won't work as you can see it is used in the TagCollection property, which can't be read only.
I tried casting the above to ITagParent<CustomerTag>, but this fails at compile time with a 'cannot convert' error when trying to feed it into my GetTagCurrentValue method.
Another option I considered is using some base classes instead of the ITagParent interface, but that won't work as the Customer object already inherits from another base class, which can't be modified for this implementation.
I know I could just overload the GetTagCurrentValue method with List<TagAddOn<CustomerTag>> as the parameter type and all other variations, but that really seems like a 'I give up' solution. I could probably use reflection to get the desired results, but that would be unwieldy and not very efficient, especially considering this method could be called a lot in a particular process.
So does anyone have any suggestions?
Could you use something like that
public class TagAddOnManager
{
public static string GetTagCurrentValue<TTag>(ITagParent<TTag> tagParent)
where TTag : ITag
{
// Just an example.
return tagParent.TagCollection.First().CurrentTag.Description;
}
}
and use it like that?`
var value = TagAddOnManager.GetTagCurrentValue((Customer)CustomergridCell.Row.Data);
I have a project where I need to construct a fair amount of configuration data before I can execute a process. During the configuration stage, it's very convenient to have the data as mutable. However, once configuration has been completed, I'd like to pass an immutable view of that data to the functional process, as that process will rely on configuration immutability for many of its computations (for instance, the ability to pre-compute things based on initial configuration.) I've come up with a possible solution using interfaces to expose a read-only view, but I'd like to know if anybody has encountered problems with this type of approach or if there are other recommendations for how to solve this problem.
One example of the pattern I'm currently using:
public interface IConfiguration
{
string Version { get; }
string VersionTag { get; }
IEnumerable<IDeviceDescriptor> Devices { get; }
IEnumerable<ICommandDescriptor> Commands { get; }
}
[DataContract]
public sealed class Configuration : IConfiguration
{
[DataMember]
public string Version { get; set; }
[DataMember]
public string VersionTag { get; set; }
[DataMember]
public List<DeviceDescriptor> Devices { get; private set; }
[DataMember]
public List<CommandDescriptor> Commands { get; private set; }
IEnumerable<IDeviceDescriptor> IConfiguration.Devices
{
get { return Devices.Cast<IDeviceDescriptor>(); }
}
IEnumerable<ICommandDescriptor> IConfiguration.Commands
{
get { return Commands.Cast<ICommandDescriptor>(); }
}
public Configuration()
{
Devices = new List<DeviceDescriptor>();
Commands = new List<CommandDescriptor>();
}
}
EDIT
Based on input from Mr. Lippert and cdhowie, I put together the following (removed some properties to simplify):
[DataContract]
public sealed class Configuration
{
private const string InstanceFrozen = "Instance is frozen";
private Data _data = new Data();
private bool _frozen;
[DataMember]
public string Version
{
get { return _data.Version; }
set
{
if (_frozen) throw new InvalidOperationException(InstanceFrozen);
_data.Version = value;
}
}
[DataMember]
public IList<DeviceDescriptor> Devices
{
get { return _data.Devices; }
private set { _data.Devices.AddRange(value); }
}
public IConfiguration Freeze()
{
if (!_frozen)
{
_frozen = true;
_data.Devices.Freeze();
foreach (var device in _data.Devices)
device.Freeze();
}
return _data;
}
[OnDeserializing]
private void OnDeserializing(StreamingContext context)
{
_data = new Data();
}
private sealed class Data : IConfiguration
{
private readonly FreezableList<DeviceDescriptor> _devices = new FreezableList<DeviceDescriptor>();
public string Version { get; set; }
public FreezableList<DeviceDescriptor> Devices
{
get { return _devices; }
}
IEnumerable<IDeviceDescriptor> IConfiguration.Devices
{
get { return _devices.Select(d => d.Freeze()); }
}
}
}
FreezableList<T> is, as you would expect, a freezable implementation of IList<T>. This gains insulation benefits, at the cost of some additional complexity.
The approach you describe works great if the "client" (the consumer of the interface) and the "server" (the provider of the class) have a mutual agreement that:
the client will be polite and not try to take advantage of the implementation details of the server
the server will be polite and not mutate the object after the client has a reference to it.
If you do not have a good working relationship between the people writing the client and the people writing the server then things go pear-shaped quickly. A rude client can of course "cast away" the immutability by casting to the public Configuration type. A rude server can hand out an immutable view and then mutate the object when the client least expects it.
A nice approach is to prevent the client from ever seeing the mutable type:
public interface IReadOnly { ... }
public abstract class Frobber : IReadOnly
{
private Frobber() {}
public class sealed FrobBuilder
{
private bool valid = true;
private RealFrobber real = new RealFrobber();
public void Mutate(...) { if (!valid) throw ... }
public IReadOnly Complete { valid = false; return real; }
}
private sealed class RealFrobber : Frobber { ... }
}
Now if you want to create and mutate a Frobber, you can make a Frobber.FrobBuilder. When you're done your mutations, you call Complete and get a read-only interface. (And then the builder becomes invalid.) Since all the mutability implementation details are hidden in a private nested class, you can't "cast away" the IReadOnly interface to RealFrobber, only to Frobber, which has no public methods!
Nor can the hostile client create their own Frobber, because Frobber is abstract and has a private constructor. The only way to make a Frobber is via the builder.
This will work, but "malicious" methods may try to cast an IConfiguration to a Configuration and thereby bypass your interface-imposed restrictions. If you're not worried about that then your approach will work fine.
I usually do something like this:
public class Foo {
private bool frozen = false;
private string something;
public string Something {
get { return something; }
set {
if (frozen)
throw new InvalidOperationException("Object is frozen.");
// validate value
something = value;
}
}
public void Freeze() {
frozen = true;
}
}
Alternatively, you could deep-clone your mutable classes into immutable classes.
Why can't you provide a separate immutable view of the object?
public class ImmutableConfiguration {
private Configuration _config;
public ImmutableConfiguration(Configuration config) { _config = config; }
public string Version { get { return _config.Version; } }
}
or if you don't like the extra typing, make the set members internal rather than public - accessible within the assembly but not by clients of it?
I'm regularly working with a large, COM-based framework (ESRI's ArcGIS Engine) that handles modifications very similarly in some situations: there are the "default" IFoo interfaces for read-only access, and IFooEdit interfaces (where applicable) for modifications.
That framework is fairly well-known, and I'm not aware of any widespread complaints about this particular design decision behind it.
Finally, I think it's definitely worth some additional thought in deciding which "perspective" gets to be the default one: the read-only perspective or the full-access one. I would personally make the read-only view the default.
How about:
struct Readonly<T>
{
private T _value;
private bool _hasValue;
public T Value
{
get
{
if (!_hasValue)
throw new InvalidOperationException();
return _value;
}
set
{
if (_hasValue)
throw new InvalidOperationException();
_value = value;
}
}
}
[DataContract]
public sealed class Configuration
{
private Readonly<string> _version;
[DataMember]
public string Version
{
get { return _version.Value; }
set { _version.Value = value; }
}
}
I called it Readonly but I'm not sure that's the best name for it though.
I have a 3rd party badly designed library that I must use.
It has all sorts of types it works with, we'll call them SomeType1, SomeType2 etc.
None of those types share a common base class but all have a property named Value with a different return type.
All I want to do is to be able to Mixin this class so I'll be able to call someType1Instance.Value and someType2Instance.Value without caring what the concreate type it is and without caring what the return type is (I can use object).
So my code is currently:
public interface ISomeType<V>
{
V Value {get; set;}
}
public interface ISomeTypeWrapper
{
object Value { get; set; }
}
public class SomeTypeWrapper<T> : ISomeTypeWrapper
where T : ISomeType<???>
{
T someType;
public SomeTypeWrapper(T wrappedSomeType)
{
someType = wrappedSomeType
}
public object Value
{
get { return someType.Value; }
set { someType.Value = value != null ? value : default(T); }
}
}
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
The problem is that I don't know what T might be until runtime due to the fact that I get a dictionary of objects.
I can iterate the dictionary and use reflection to create a SomeWrapperType on runtime but I would like to avoid it.
How can I mixin the concreate type of SomeType to ISomeType?
How can I know what V type parameter is? (wish I had typedefs and decltype like in c++)
How can I, with the minimum of use of reflection possible Mixin those classes with the interface/base class?
You could try the Duck Typing Extensions for Windsor. It means you will need to register each of your types.
container
.Register(Component.For(typeof(SomeType1)).Duck<ISomeType>())
.Register(Component.For(typeof(SomeType2)).Duck<ISomeType>());
You could probably use linq and the register AllTypes syntax to reduce code if the names are similar.
Alternatively in the short term create a factory which can return you the objects you need, implement a concrete object for each type. No you are using the interface you can remove the factory at a later date and replace it with something else with minimal impact:
public class SomeTypeWrapperFactory
{
public ISomeType<int> CreateWrapper(SomeType1 someType1)
{
return new SomeType1Wrapper(someType1);
}
public ISomeType<string> CreateWrapper(SomeType2 someType2)
{
return new SomeType2Wrapper(someType2);
}
}
public class SomeType1Wrapper : ISomeType<int> { ... }
public class SomeType2Wrapper : ISomeType<int> { ... }
Regardless of how you implement the wrapper, be the individually or using a god like class you have the ability to change how the wrapping is done and keep the rest of your code clean.
Why SomeTypeWrapper but not SomeObjectWrapper?
public class SomeObjectWrapper : ISomeType
{
Object _someObject;
PropertyInfo _valuePropertyInfo;
public SomeObjectWrapper(Object wrappedSomeObject)
{
_someObject = wrappedSomeObject;
_valuePropertyInfo = _someObject.GetType().GetProperty("Value", System.Reflection.BindingFlags.Public);
}
public object Value
{
get { return _valuePropertyInfo.GetValue(_someObject, null); }
set { _valuePropertyInfo.SetValue(_someObject, value, null); }
}
}
Edited With .NET 3.5 using LinFu
You may use LinFu instead of Castle. However, you would be using reflection anyway, both with Castle's and with Linfu's DynamicProxy, only hidden in the guts of the libraries instead of being exposed in your code. So if your requirement to avoid the use of reflection is out of performance concerns, you wouldn't really avoid it with this solution.
In that case I would personally choose Orsol's solution.
However: here's an example with LinFu's ducktyping.
public interface ISomeType {
object Value{get; set;}
}
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
public class SomeTypeWrapperFactory
{
public static ISomeType CreateSomeTypeWrapper(object aSomeType)
{
return aSomeType.CreateDuck<ISomeType>();
}
}
class Program
{
public static void Main(string[] args)
{
var someTypes = new object[] {
new SomeType1() {Value=1},
new SomeType2() {Value="test"}
};
foreach(var o in someTypes)
{
Console.WriteLine(SomeTypeWrapperFactory.CreateSomeTypeWrapper(o).Value);
}
Console.ReadLine();
}
}
Since you don't know the type of the SomeType's until runtime, I would not use mixins, but the visitor pattern (I know this doesn't answer the question on how to use mixins for this, but I just thought I'd throw in my 2 cents).
With .NET 4 using dynamic
See Bradley Grainger's post here on using c#4's dynamic keyword to implement the visitor pattern.
In your case, reading all the "Value" properties from your dictionary of SomeType's could work like this:
public class SomeType1
{
public int Value { get; set; }
}
public class SomeType2
{
public string Value { get; set; }
}
public class SomeTypeVisitor
{
public void VisitAll(object[] someTypes)
{
foreach(var o in someTypes) {
// this should be in a try-catch block
Console.WriteLine(((dynamic) o).Value);
}
}
}
class Program
{
public static void Main(string[] args)
{
var someTypes = new object[] {
new SomeType1() {Value=1},
new SomeType2() {Value="test"}
};
var vis = new SomeTypeVisitor();
vis.VisitAll(someTypes);
}
}