Typed<>/untyped design - c#

I have an (existing) typed class of items:
Items<T>
T Value { get; }
T can be double, string or int.
I then have a class that has to hold several instances of Items. Within a single instance of this class, T is always the same. As it stands, the type actually contained is determined by a property and the container is not typed:
Data
DataType { get; set; }
Items<double>
double Value;
Items<string>
// ... and so on. Nasty stuff.
Ideally, of course, this would be
Data<T>
Items<T>
T value
Data instances are created from scratch in code, and can be loaded from a database. So of course a factory would be in our future, but what is the return type of the Create method?
Even worse, I need this:
DataCollection
// HERE'S THE PAIN: What's the type here?
List of Data<> instances with differing types
foreach (? data in someDataCollection)
if (thetypeof data is double)
doSomething();
else
doSomethingElse();
Now, I can solve this, but I can't see a CLEAN way to solve this.
My first issue is the declaration of DataCollection. What is the type of the list? List<object>, so it can hold Data<double> and Data<string>?

There actually is a clean way to solve this; you can use a Dictionary with keys of the data type and values which are of type generic Func<> . You then pass the type to your create method, which then looks up the Func<> to use in the Dictionary based on the type, and invokes that Func<> to create or process your object.
Since I am working from pseudo code, basically it would look something like the below; you can play with it and modify it to get it to serve your needs, but this is the basic idea.
First, create a parent class for all data objects; note that this class has a lookup dictionary for functions to invoke on various types, and note that it is abstract:
public abstract class Data
{
// A Lookup dictionary for processing methods
// Note this the functions just return something of type object; specialize as needed
private static readonly IDictionary<Type, Func<object, Data>> _processFunctions = new Dictionary
<Type, Func<object, Data>>()
{
{typeof(int), d => { return doSomethingForInt( (Data<int>) d); }},
{typeof(string), d => { return doSomethingForString( (Data<string>) d); }},
{typeof(double), d => { return doSomethingForDouble( (Data<double>) d); }},
};
// A field indicating the subtype; this will be used for lo
private readonly Type TypeOfThis;
protected Data(Type genericType)
{
TypeOfThis = genericType;
}
public Data Process()
{
return _processFunctions[this.TypeOfThis](this);
}
}
Now subclass Data with a generic type that can be instantiated:
class Data<T> : Data
{
// Set the type on the parent class
public Data() : base(typeof(T))
{
}
// You can convert this to a collection, etc. as needed
public T Items { get; set; }
public static Data<T> CreateData<T>()
{
return new Data<T>();
}
}
You can then create a DataCollection class using the parent type. Note the ProcessData() method; all it does now is loop over the elements and call Process() on each one:
class DataCollection
{
public IList<Data> List = new List<Data>();
public void ProcessData()
{
foreach (var d in List)
{
d.Process();
}
}
}
...and you're all set! Now you can invoke your DataCollection with different types of Data:
DataCollection dc = new DataCollection();
dc.List.Add(new Data<int>());
dc.List.Add(new Data<string>());
dc.List.Add(new Data<double>());
dc.ProcessData();

I think every time you need to do if-conditions on runtime data type, it means there's something wrong with the data structures. But every time I encounter situation like this, I have a hard time to solve it.
What I would try to do here is to wrap your primitive types into some kind of Adapters with conversion methods (possibly even implicit) and make all of them implement a common interface, let's say IDoSomething. Then, you can define the doSomething behaviors in IntWrapper, DoubleWrapper etc. separately. Then your DataCollection should be of type List<IDoSomething> and the loop can just call data.DoSomething() method from the interface.
Having implicit conversion allows you to use the collection in the natural way like data.Add(3) - you'll still be able to add the items without wrapping the privitives

Related

ReSharper warns: "Static field in generic type"

public class EnumRouteConstraint<T> : IRouteConstraint
where T : struct
{
private static readonly Lazy<HashSet<string>> _enumNames; // <--
static EnumRouteConstraint()
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException(
Resources.Error.EnumRouteConstraint.FormatWith(typeof(T).FullName));
}
string[] names = Enum.GetNames(typeof(T));
_enumNames = new Lazy<HashSet<string>>(() => new HashSet<string>
(
names.Select(name => name), StringComparer.InvariantCultureIgnoreCase
));
}
public bool Match(HttpContextBase httpContext, Route route,
string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
bool match = _enumNames.Value.Contains(values[parameterName].ToString());
return match;
}
}
Is this wrong? I would assume that this actually has a static readonly field for each of the possible EnumRouteConstraint<T> that I happen to instance.
It's fine to have a static field in a generic type, so long as you know that you'll really get one field per combination of type arguments. My guess is that R# is just warning you in case you weren't aware of that.
Here's an example of that:
using System;
public class Generic<T>
{
// Of course we wouldn't normally have public fields, but...
public static int Foo;
}
public class Test
{
public static void Main()
{
Generic<string>.Foo = 20;
Generic<object>.Foo = 10;
Console.WriteLine(Generic<string>.Foo); // 20
}
}
As you can see, Generic<string>.Foo is a different field from Generic<object>.Foo - they hold separate values.
From the JetBrains wiki:
In the vast majority of cases, having a static field in a generic type
is a sign of an error. The reason for this is that a static field in a
generic type will not be shared among instances of different close
constructed types. This means that for a generic class C<T> which
has a static field X, the values of C<int>.X and C<string>.X
have completely different, independent values.
In the rare cases when you do need the 'specialized' static fields,
feel free to suppress the warning.
If you need to have a static field shared between instances with
different generic arguments, define a non-generic base class to
store your static members, then set your generic type to inherit from
this type.
This is not necessarily an error - it is warning you about a potential misunderstanding of C# generics.
The easiest way to remember what generics do is the following:
Generics are "blueprints" for creating classes, much like classes are "blueprints" for creating objects. (Well, this is a simplification though. You may use method generics as well.)
From this point of view MyClassRecipe<T> is not a class -- it is a recipe, a blueprint, of what your class would look like. Once you substitute T with something concrete, say int, string, etc., you get a class. It is perfectly legal to have a static member (field, property, method) declared in your newly created class (as in any other class) and no sign of any error here.
It would be somewhat suspicious, at first sight, if you declare static MyStaticProperty<T> Property { get; set; } within your class blueprint, but this is legal too. Your property would be parameterized, or templated, as well.
No wonder in VB statics are called shared. In this case however, you should be aware that such "shared" members are only shared among instances of the same exact class, and not among the distinct classes produced by substituting <T> with something else.
There are several good answers here already, that explain the warning and the reason for it. Several of these state something like having a static field in a generic type generally a mistake.
I thought I'd add an example of how this feature can be useful, i.e. a case where suppressing the R#-warning makes sense.
Imagine you have a set of entity-classes that you want to serialize, say to Xml. You can create a serializer for this using new XmlSerializerFactory().CreateSerializer(typeof(SomeClass)), but then you will have to create a separate serializer for each type. Using generics, you can replace that with the following, which you can place in a generic class that entities can derive from:
new XmlSerializerFactory().CreateSerializer(typeof(T))
Since your probably don't want to generate a new serializer each time you need to serialize an instance of a particular type, you might add this:
public class SerializableEntity<T>
{
// ReSharper disable once StaticMemberInGenericType
private static XmlSerializer _typeSpecificSerializer;
private static XmlSerializer TypeSpecificSerializer
{
get
{
// Only create an instance the first time. In practice,
// that will mean once for each variation of T that is used,
// as each will cause a new class to be created.
if ((_typeSpecificSerializer == null))
{
_typeSpecificSerializer =
new XmlSerializerFactory().CreateSerializer(typeof(T));
}
return _typeSpecificSerializer;
}
}
public virtual string Serialize()
{
// .... prepare for serializing...
// Access _typeSpecificSerializer via the property,
// and call the Serialize method, which depends on
// the specific type T of "this":
TypeSpecificSerializer.Serialize(xmlWriter, this);
}
}
If this class was NOT generic, then each instance of the class would use the same _typeSpecificSerializer.
Since it IS generic however, a set of instances with the same type for T will share a single instance of _typeSpecificSerializer (which will have been created for that specific type), while instances with a different type for T will use different instances of _typeSpecificSerializer.
An example
Provided the two classes that extend SerializableEntity<T>:
// Note that T is MyFirstEntity
public class MyFirstEntity : SerializableEntity<MyFirstEntity>
{
public string SomeValue { get; set; }
}
// Note that T is OtherEntity
public class OtherEntity : SerializableEntity<OtherEntity >
{
public int OtherValue { get; set; }
}
... let's use them:
var firstInst = new MyFirstEntity{ SomeValue = "Foo" };
var secondInst = new MyFirstEntity{ SomeValue = "Bar" };
var thirdInst = new OtherEntity { OtherValue = 123 };
var fourthInst = new OtherEntity { OtherValue = 456 };
var xmlData1 = firstInst.Serialize();
var xmlData2 = secondInst.Serialize();
var xmlData3 = thirdInst.Serialize();
var xmlData4 = fourthInst.Serialize();
In this case, under the hood, firstInst and secondInst will be instances of the same class (namely SerializableEntity<MyFirstEntity>), and as such, they will share an instance of _typeSpecificSerializer.
thirdInst and fourthInst are instances of a different class (SerializableEntity<OtherEntity>), and so will share an instance of _typeSpecificSerializer that is different from the other two.
This means you get different serializer-instances for each of your entity types, while still keeping them static within the context of each actual type (i.e., shared among instances that are of a specific type).

Producing an abstract collection from an abstract collection

This issue has been bugging me for a while. Abstractly speaking, regardless of language, there are often situations when you want to have a method like this:
Collection method(Collection c) {
// select some elements from c based on some filter
// and return a new collection
}
Now, Collection is in this case some abstract class (Like say IList in C# or List in Java) with several implementations. I've been wondering what exactly is the right procedure to produce the abstract collection?
Is it ok to create a concrete collection inside the method and return it? Like:
Collection method(Collection c) {
Collection cc = new ConcreteCollection();
// select some elements from c based on some filter
return cc;
}
This of course puts a constraint on the resulting collection and will produce problems in case, for some reason, we want to cast the result of the method to a different concrete collection than the one used inside the method.
Or, use reflection to determine the actual concrete type of c and create an instance of that class:
Collection method(Collection c) {
Collection cc = c.getClass().newInstance();
// select some elements from c based on some filter
return cc;
}
For some reason this does not seem very "elegant" to me. I would greatly appreciate some insight in this matter.
(Speaking for java). The reason you're returning Collection (an interface) rather than a concrete type (such as ArrayList) is that you're telling the user that they shouldn't care about what the actual concrete type being used is. This leaves you free to choose the appropriate type for your library/api.
If you're enforcing a particular concrete class, then you should be returning that concrete class, rather than the interface.
So, they shouldn't be casting your return type to anything else other than Collection. See
When should I return the Interface and when the concrete class?.
In Java, there are actually some good examples of how to do this in the java.util.Collections class. Instead of taking a Collection and returning a Collection, the key methods take two collections, the "src" and the "dest". For example, Look at the signature of the copy method:
public static <T> void copy(List<? super T> dest, List<? extends T> src)
This puts the responsibility of instantiating the destination list on the caller.
I think you could do the same thing when you want to create a method that acts on a src Collection and puts the results into a destination Collection (rather than Lists).
I agree with Matthew Farwell's answer that you probably just want to return the interface and utilize that, but for the times when you really do need to work with a specific implementing class you can do it the same way the Collections class does it.
One approach you could take is to create a Collection implementation that delegates calls through to the original Collection. This defers the potentially expensive operation of filtering a large Collection until you need to explicitly read elements. It also saves memory.
Example
public interface Filter<T> {
boolean include(T t);
}
public class FilterCollection<T> implements Collection<T> {
private final Collection<T> orig;
private final Filter<T> filter;
public FilterCollection(Collection<T> orig, Filter<T> filter) {
this.orig = orig;
this.filter = filter;
}
public int size() {
int sz = 0;
for (T t : orig) {
if (filter.include(t)) {
++sz;
}
}
return sz;
}
public boolean contains(Object o) {
return o instanceof T && filter.include((T) o) && orig.contains(o);
}
public boolean add(T t) {
if (!filter.include(t)) {
throw new IllegalArgumentException("Element lies outside filter bounds.");
}
orig.add(t);
}
}
The caller should assume a given type of Collection is returned.
Instead it should either copy to the desired type or pass the desired type.
e.g.
Set<T> set2 = new HashSet<T>(filter(set));
List<T> list2 = new ArrayList<T>(filter(list));
or
filter(set2, set); // the target collection is passed.
filter(list2, list);
To the question about ConcreteCollection, it is definitely allowable.
To the concern about having a different concrete collection expected, there are a few ways to go around the problem:
Change the return type of the method. Example:
ConcreteCollection method(Collection c){
ConcreteCollection cc=new ConcreteCollection
for(Object x: c){
//do something
}
return cc
}
Make use of polymorphism. Example:
Collection x=method(c)
x.add(new Object) //add is a method defined within the abstract Collection
Use some utilities to cast the type. Example:
LinkedList h=Collections.toLinkedList(method(c))
Hoped my answer helped. ^^
As far as I can understand, you want to know how to make a method that accepts generic list and returns another modified generic list.
So, my advice will be to use an abstract type that implements method to modify its state.
IList<object> list = new List<object>();
list.Add(new object());
list.Remove(obj);
Or as showed above, instantiate a list that implements IList (or the Java equivalent) work with this instance and return the result as a IList
Edit
If you want to filter some item from a list to a new one, generics can help (I don't know if this feature exists in Java).
public IList<T> Filter<T>(IList<T> list)
{
var result = new List<T>();
result.Add(list[0]); // Or whatever filtering method
return result;
}
If you want your method to accept as many different collection types as possible, and you want to be sure that the result is the same implementation type as what you put in, you might want to use a void method which directly modifies the supplied collection. For instance:
import com.google.common.base.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class Testy {
private static <T> void filter(Iterable<T> collection, Predicate<T> filter) {
Iterator<T> iterator = collection.iterator();
while (iterator.hasNext()) {
if (!filter.apply(iterator.next())) { // Condition goes here
iterator.remove();
}
}
}
public static void main(String... args) {
List<String> list = new ArrayList<String>();
list.addAll(Arrays.asList("A", "B", "C", "D"));
filter(list, new Predicate<String>() { // Anonymous filter (predicate)
#Override public boolean apply(String input) {
return input.equals("B");
}
});
System.out.println(list); // Prints ["B"]
}
}
The helper method filter takes an Iterable, the simplest type required for iterating over something. Apply the filter to each element, and if the predicate (filter) returns false, remove that element from the underlying collection with Iterator.remove().
The Predicate<T> interface here comes from Google. You can easily write your own if you don't wish to import it. The only required method is apply(T) which returns a boolean. Either that, or just write your condition directly inside the loop and get rid of the second parameter.
This method is the most efficient if your original collection is mutable and you don't wish to keep any intermediate results.
Another option is to use Google Collections Collections2.filter(Collection<E>, Predicate<E>) which returns a Collection<E> just like in your question. Similarly, the Iterables class will do the same thing, but create lazy iterables where the filters are only applied when actually doing the iterating.

How am I able to create A List<T> containing an open generic Interface?

I have a List which must contain IInteract Objects. But IInteract is a generic interface which requires 2 type arguments.
My main idea is iterate through a list of Objects and "Interact" one with another if they didn't interact yet.
So i have this object
List<IObject> WorldObjects = new List<IObject>();
and this one:
private List<IInteract> = new List<IInteract>();
Except I can't compile the last line because IInteract requires 2 type arguments. But I don't know what the arguments are until I add them. I could add interactions between Objects of Type A and A... or Objects of Type B and C.
I want to create "Interaction" classes which do something with the "acting" object and the "target" object, but I want them to be independent from the objects... so I could add an Interaction between for instance... "SuperUltraClass" and... an "integer".
Am I using the wrong approach?
Assuming IInteract is defined as something like
interface IInteract<T1, T2>
and you are using it for a field of a class Foo:
class Foo
{
List<IInteract...> field;
}
Then if you want to defer the decision of what types to bind to the IInteract type arguements you need to parameterize the container class:
class Foo<T1, T2>
{
List<IInteract<T1, T2>> field;
}
The type arguments to IInteract here will be bound when you define a concrete instantiation of the container class, like: var x = new Foo<int, double>(). This will cause the IInteract field to be of type IInteract<int, double> for that particular instantiation of the Foo generic type.
I think an interface hierarchy might make things easier. The top-level could be a non-generic interface with just the methods that you need to invoke, absent any type information. The second level would be those that required some typing...of course, it may be enough to simply have the implementing class instead of the second level interface.
public interface IInteract
{
void Interact();
}
public interface IInteract<TActor,TTarget> : IInteract
{
TActor Actor { get; set; }
TTarget Target { get; set; }
}
Then you can create your list of IInteract objects and it can contain any of the strongly typed IInteract<TActor,TTarget> objects, though only those methods on the non-generic interface will be available. The important thing will be the concrete implementations -- that is what will determine what code gets executed anyway.
I think you should use an inversion of control container (I've used Castle Windsor in the past). Then you can do something like this:
void Interact<TA, TB>(TA objectA, TB objectB)
{
var interact = Container.Resolve<IInteract<TA, TB>>();
interact.Interact(objectA, objectB);
}
you can do this:
private List<IInteract<SomeType, SomeOtherType>> = new List<IInteract<SomeType, SomeOtherType>>();
But like you said you don't know what types you're adding. So here are a couple of options:
1: Use object (or even dynamic) types:
private List<IInteract<object, object>> ...
2: Use generics in your class:
class Foo<T1, T2> {
private List<IInteract<T1, T2>> ...
}
...
Foo<string, int> bar = new Foo<string, int>();
In the second example you are locked into adding only strings and ints (or whatever you create the Foo object to be) to your list. In the first example you can mix and match, but you would have to do runtime type checking to figure out what you're pulling out of the list.
I'm not sure I completely understand what you're trying to accomplish. What you need to do is create a concrete class which implements your interface, and then use that in your List<>. Like so:
public interface IInteract
{
Type A { get; set; }
Type B { get; set; }
}
public class Interact : IInteract
{
public Type A
{
get { return a; }
}
public Type B
{
get { return b; }
}
}
And then use your concrete class in your list:
private List<Interact> = new List<Interact>();
You might be better off using a dictionary, where the key is a tuple of the two types that you are interacting, and the values are Interact, so each Interact implementation would have to do some casting
private Dictionary<Tuple<Type, Type>, IInteract<Object, Object>> interactions = new Dictionary<Tuple<Type, Type>, IInteract<Object, Object>>();
It's a bit messy but then you can add to it:
IInteract<Object, Object> superClassIntInteraction = someInteractionClass;
interactions.Add(new Tuple<Type, Type>(typeof(SuperClass),typeof(int)), superClassIntInteraction);
I'm assuming that you want to be able to search the list/dictionary to be able to find a specific interaction later on, which is where the dictionary comes in handy

is this possible: c# collection of Type with constrains, or collection of generic type?

I'm trying to store types in a collection, so that i can later instantiate objects of the types in the collection. But I'm not sure how to do this the best way.
What i have so far:
List<Type> list = new List<Type>();
list.Add(typeof(MyClass));
var obj = (MyClass)Activator.CreateInstance(list[0]);
I would like to have some constrains on the Type, or better yet, just a generic type in the collection instead of an instantiated Type object. Is this possible?
That's not how generic collection constraints work.
Generic constraints restrict which types are legal for instantiating a generic type. There are several different kinds of constraints, but the common ones limit a generic parameter to either inherit or be an instance of a given type, or be a type that implements a particular interface (or set of interfaces).
Type, on the other hand, is a class that describes information about a type in your application or one of it's libraries. Specific kinds of types don't inherit or extend Type - rather there is a different instance of Type for each type available. You cannot use generic constraints to control which instances of Type may be added to your collection.
Without more detail about how you want to "constrain" the information in the collection, it's hard to say what route you should take. For example, if all you want to do is ensure that only unique types (no dups) are stored, that can be achieved with a HashSet (rather than a list). But if you want something more specialized - like limiting the Type instances that can be added to some subset of types, then you will likely need to implement your own collection, and implement gaurd logic in the Add/Insert methods.
In this particular scenario, where it seems we have a "factory" pattern, we would constrain the method invoking the activator, such as
private readonly List<Type> _supportedTypes = new List<Type> ();
public void RegisterSupportedType<T> () where T : SomeConstraintType
{
_supportedTypes.Add (typeof (T));
}
// if we do not know the type, but somehow know an index to type
public object Create (int supportedTypeIndex)
{
object untyped = Activator.
CreateInstance (_supportedTypes[supportedTypeIndex]);
return untyped;
}
// if we know instance type\subtype (eg interface) and know an index
public T Create<T> (int supportedTypeIndex)
{
T typed = default (T);
object untyped = Create (supportedTypeIndex);
if (!(untyped is T))
{
// throw meaningful exception :)
}
typed = (T)(untyped);
return typed;
}
An alternative, is to create a constrained Type
public class ConstrainedType<T>
{
public Type Type { get; private set; }
public ConstrainedType (Type type)
{
// may have this backward, would have to fact check before
// rolling out to prod ;)
if (!typeof (T).IsAssignableFrom (type))
{
// throw meaningful exception!
}
Type = type;
}
}
List<ConstrainedType<SomeTypeConstraint>> list =
new List<ConstrainedType<SomeTypeConstraint>> ();
// will throw meaningful exception if MyClass is not
// SomeTypeConstraint or a sub class
list.Add (new ConstrainedType (typeof (MyClass)));
SomeTypeConstraint baseType =
(SomeTypeConstraint)(Activator.CreateInstance(list[0].Type));
Jon,
If you are using CodeContracts, you could require a number of known types. The code analysis would flag any calls to your collection with invalid types.
public class TypeCollection : List<Type>
{
public TypeCollection()
{
}
public new void Add(Type type)
{
Contract.Requires(type == typeof(string) || type == typeof(Stream));
base.Add(type);
}
}
public class TestCollection
{
public void Test()
{
TypeCollection collection = new TypeCollection();
// This gets compile time warning:
collection.Add(typeof(int));
}
}
But, if you know the types in advance, it might make more sense to specify them all in an enum and create a collection of valid enums for the type creation you want to support.
first way(seems stupid but it is safe):
(create a wrapper over the List || implement IList) and check .Exists(item) in the .Add Method.
If you were to implement your own collection, you could use generic type constraints:
public class MyList<T>
where T : IMyConstraint

Casting generic object array to two types

I've got a method that receives an Object[] and then performs actions on that array.
At first I was passing in this array as an IEnumerable<T> however the T can be of two different types.
The T's will always have the same properties, even thought they're different types.
Is it possible to cast to a a type at runtime so that I can used the properties i know each one will contain?
So where as it's possible to do:
var dataObject = (IEnumerable<T>) dataArray;
Is it somehow possible to do:
var dataObject = (dataArray.GetType()) dataArray;
Are you able to modify the source code of the two T types? If so then you could make both of them either (a) inherit from a common base class or (b) implement a common interface.
Edit following comments...
To accomodate different types for the ID property you could use explicit interface implementation. This would allow you to expose the second object's ID as an Int64 when accessed via the common interface. (The ID property would remain accessible as an Int32 when not accessed through the interface.)
Unfortunately the explicit interface implementation will require more changes to your original types.
void YourMethod(IEnumerable<ICommonToBothTypes> sequence)
{
foreach (var item in sequence)
{
Console.WriteLine(item.ID);
}
}
// ...
public interface ICommonToBothTypes
{
long ID { get; }
}
public class FirstType : ICommonToBothTypes
{
public long ID
{
get { return long.MaxValue; }
}
}
public class SecondType : ICommonToBothTypes
{
// the real Int32 ID
public int ID
{
get { return int.MaxValue; }
}
// explicit interface implementation to expose ID as an Int64
long ICommonToBothTypes.ID
{
get { return (long)ID; }
}
}
You can just create it as an interface and have both of those classes implement the interface. Then take Interface[] as the parameter instead of Object and you avoid casting all together.
If the two objects in the array derive from the same base type (inheritance) then you can box all the objects in your array as base class objects and you can use them with no knowledge of which particular object it might be.
See here for Boxing and Unboxing information from Microsoft
This is in essence what polymorphism is about, handling objects with a common interface.
Either inheritance from the same base class or creating an interface that both objects support will suit in this case. You will then be able to specifically define your array with either the base class type or the interface type, rather than "object".
If it's impossible to have the different classes all inherit the same interface, you can get all the properties defined in an object as a collection and then their value through key lookup where the key is the name of the property. I'd implement this as extension methods like so:
public static Dictionary<string, object> GetProperties<T>(this T instance)
where T : class
{
var values = new Dictionary<string, object>();
var properties =
instance.GetType().GetProperties(BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.GetProperty);
foreach (var property in properties)
{
var accessors = property.GetAccessors();
if ((accessors == null) || (accessors.Length == 0))
continue;
string key = property.Name;
object value = property.GetValue(instance, null);
values.Add(key, value);
}
return values;
}
Then you can just do like this to get the property values:
void DoStuff(object[] objects)
{
foreach (var o in objects)
{
var properties = o.GetProperties();
var value = properties["PropertyName"];
}
}
It will all be untyped and you'll break things when renaming properties if you forget to also rename the lookup keys in the consuming code, but otherwise, this should work fine. However, the best solution is undoubtedly the one suggested by Luke (using interfaces).
If you have access to the sourcecode defining the two element types
You should introduce a new interace containing the common properties and let the other two interfaces inherit from your new base interface.
In your method you then use IEnumerable.Cast(TResult) to cast all elements to the common interface:
var dataObject = dataArray as IEnumerable;
if (dataObject != null)
{
var data = dataObject.Cast<ICommonBase>()
// do something with data
}
If you can't modify the sourcecode defining the two element types:
Use the IEnumerable.OfType() to filter elements based on their known types, effectively creating two strongly typed collections. Next perform the same operations with each of them (most verbose approach).
var dataObject = dataArray as IEnumerable;
if (dataObject != null)
{
var a = dataObject.OfType<InterfaceA>()
// do something with a
var b = dataObject.OfType<InterfaceB>()
// do the same with b
}
A reference of the functions used can be found on msdn.
If you want to avoid code duplication your only chance will be to use something called duck typing.Phil Haack has a great article on it.
The idea is to introduce a new interface that contains the common elements. You then duck-type the array elements, effectively making them comply to the new interface at runtime.
The last option would be using reflection and extracting property infos by common names and then access each elements data. This is the slowest and IMHO most cumbersome approach.

Categories