For starters, I have implemented a workaround to this question based on having multiple private variables store information, and get/set on the affected object.
The scope of this questions is for learning/reference.
Scenario:
I have an interface that manages multiple objects (2 in this example).
interface Imoon
??? SomePropertyName {get;set;}
class Foo : Imoon
public TypeA SomePropertyName {get;set;}
public enumMyType TypeStorage {get;set}
class Bar : Imoon
public TypeB SomePropertyName {get;set;}
public enumMyType TypeStorage {get;set;}
The goal is to be able to reference a list/dictionary/array of objects that may change in type (similiar to a generic). The types don't impact the logic, they are partitioned into separate handlers and managed there.
Once declared, the type of the object does not change.
The Type is the same for all elements within the Enumerable, however may change between different objects.
Example declarations:
Dictionary<string,TypeA> myDictionary;
Dictionary<string,TypeB> myDictionary;
or as a list:
class Foo
List<TypeA> myValues
List<string> myKeys
class Bar
List<TypeB> myValues
List<string> myKeys
If anyone has any suggestions on how to implement this, or suggestions for improvement please let me know :)
For Archiving, I was able to reach the desired result by using a Generic interface as Recommended by johnny5 above.
I've included a example of the solution, and how to implement it with a given type (TypeA), and it could be done on TypeB aswell.
public interface ICollection<T>
{
Dictionary<string,T> TypeDictionary { get; set; }
void AddToDictionary(Dictionary<string,T> Addition
int FileCount { get; }
}
public class TypeACollection : ICollection<TypeA>
{
private Dictionary<string,TypeA> myTypeDictionary = new Dictionary<string, TypeA>();
public void AddToDictionary(Dictionary<string, TypeA> Addition)
{
foreach (var keyValuePair in Addition)
{
TypeDictionary[keyValuePair.Key] = keyValuePair.Value;
}
}
public Dictionary<string, TypeA> GetTypeDictionary()
{
return TypeDictionary;
}
private void ClearDictionary()
{
TypeDictionary.Clear();
}
public Dictionary<string, TypeA> TypeDictionary {
get { return myTypeDictionary; }
set { myTypeDictionary = value; }
}
public int FileCount {get { return TypeDictionary.Keys.Count; }}
}
public class TypeA { }
public class TypeB { }
Related
I've found couple of questions on the same topic here, however I couldn't find what I need. Basically I am searching for this kind of magic:
public class BaseClass
{
public int DerivedТype { get; set; }
}
public class DerivedClass<T> : BaseClass
{
public DerivedClass(T initialValue)
{
DerivedТype = 1;
Property = initialValue;
}
public T Property { get; set; }
}
public class OtherDerivedClass<T> : BaseClass
{
public OtherDerivedClass(T initialValue)
{
DerivedТype = 2;
OtherProperty = initialValue;
}
public T OtherProperty { get; set; }
public int OtherProperty2 { get; set; }
public float OtherProperty { get; set; }
}
public class Program
{
public static void Main()
{
List<BaseClass> baseClassList = new List<BaseClass>();
baseClassList.Add(new DerivedClass<int>(5));
baseClassList.Add(new OtherDerivedClass<float>(6));
foreach (var derived in baseClassList)
{
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
}
}
}
I want a list of BaseClass where I can insert instances of DerivedClass and OtherDerivedClass. So far so good.
DerivedClass and OtherDerivedClass hold different properties so I really have no idea how access them. Also I don't want to use any weired casts. So this part of the code prevents me from building.
if (derived.DerivedТype == 1)
{
Console.WriteLine(derived.Property);
}
else if (derived.DerivedТype == 2)
{
Console.WriteLine(derived.OtherProperty);
}
Any ideas would be appreciated. Thank you in advance!
This looks like a problem that can be solved with polymorphism. I'll make a version of your app that does exactly what you seem to be doing in your example, but if there was more information as to what your target goal is, the solution may be different.
public abstract class BaseClass
{
public abstract void DoSomething();
public abstract void GetData(Dictionary<string,string> container);
}
public class DerivedClass<T> : BaseClass
{
public DerivedClass(T initialValue)
{
Property = initialValue;
}
public T Property { get; set; }
public override void DoSomething()
{
Console.WriteLine(Property);
}
public override void GetData(Dictionary<string,string> container)
{
container.Add(nameof(Property), "{Property}");
}
}
public class OtherDerivedClass<T> : BaseClass
{
public OtherDerivedClass(T initialValue)
{
OtherProperty = initialValue;
}
public T OtherProperty { get; set; }
public int OtherProperty2 { get; set; }
public override void DoSomething()
{
Console.WriteLine(OtherProperty);
}
public override void GetData(Dictionary<string,string> container)
{
container.Add(nameof(OtherProperty), "{OtherProperty}");
container.Add(nameof(OtherProperty2), "{OtherProperty2}");
}
}
Your foreach loop could then be as simple as:
foreach(var derived in baseClassList) derived.DoSomething();
This is the proper way to do something like this using OO. There's no need for the DerivedType integer since the object knows what type of class it is and what to do. This is why one would use polymorphism. It's simple and elegant and OO. Extend or change the DoSomething to be more appropriate for what you're trying to do.
The OP came up with his own solution, but if the goal is to do something with the data that is more meaningful, you could also pass in an object to an abstract method that allows you to do this. I added a GetData method that will return all of the property values as strings. The second type of the dictionary could also be object with the actual value stored in the dictionary.
BaseClass could also be a regular class with a method in it to return an IDictionary of object values with string keys. The method could use reflection to get all property values for whatever class it is the base of. Reflection has much more overhead, though, so is not the most efficient way to do this from an execution standpoint.
The correct way to check if an object is a certain type is to use the is operator such as:
if(derived is DerivedType<int>)
{
// Do what you need to do with the specific object type
}
If you know you're going to cast the object, as pointed out by Adosi, you would use:
var castedValue = derived as DerivedType<int>;
if(castedValue != null)
{
// Do what you need to do with castedValue
}
A null will be returned if the object isn't of type DerivedType<int>. Trying to use (DerivedType)derived would cause an invalid cast exception.
To the best of my knowledge what you want is between impossible and not a good idea. Typechecking is done at compile time. Stuff like Dynamic can move those checks to runtime, but it results in all kinds of issues (functions that take dynamic parameters also return dynamic).
If you got at least C# 7.0, you can at least write a switch for it. Old switch only supported values vs constants for a few select value types and string. But C# 7.0 introduces pattern matching. With that you could even use a is check as part of a case.
Thank you all for the awesome support! I decided to go simple and just use a cast.
public class BaseClass
{
public int DataТype { get; set; }
public object Data { get; set; }
}
public class DataClass<T>
{
public DataClass(T initialValue)
{
Property = initialValue;
}
public T Property { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
List<BaseClass> listBaseClass = new List<BaseClass>();
BaseClass dummy = new BaseClass();
dummy.DataТype = 1;
dummy.Data = new DataClass<int>(50);
listBaseClass.Add(dummy);
if (listBaseClass[0].DataТype == 1)
{
DataClass<int> casted = (DataClass<int>)listBaseClass[0].Data;
Console.WriteLine(casted.Property);
}
}
}
Is it possible to add different type of generic objects to a list?. As below.
public class ValuePair<T>
{
public string Name { get; set;}
public T Value { get; set;
}
and let say I have all these objects...
ValuePair<string> data1 = new ValuePair<string>();
ValuePair<double> data2 = new ValuePair<double>();
ValuePair<int> data3 = new ValuePair<int>();
I would like to hold these objects in a generic list.such as
List<ValuePair> list = new List<ValuePair>();
list.Add(data1);
list.Add(data2);
list.Add(data3);
Is it possible?
In general, you'd have to either use a List<object> or create a non-generic base class, e.g.
public abstract class ValuePair
{
public string Name { get; set;}
public abstract object RawValue { get; }
}
public class ValuePair<T> : ValuePair
{
public T Value { get; set; }
public object RawValue { get { return Value; } }
}
Then you can have a List<ValuePair>.
Now, there is one exception to this: covariant/contravariant types in C# 4. For example, you can write:
var streamSequenceList = new List<IEnumerable<Stream>>();
IEnumerable<MemoryStream> memoryStreams = null; // For simplicity
IEnumerable<NetworkStream> networkStreams = null; // For simplicity
IEnumerable<Stream> streams = null; // For simplicity
streamSequenceList.Add(memoryStreams);
streamSequenceList.Add(networkStreams);
streamSequenceList.Add(streams);
This isn't applicable in your case because:
You're using a generic class, not an interface
You couldn't change it into a generic covariant interface because you've got T going "in" and "out" of the API
You're using value types as type arguments, and those don't work with generic variable (so an IEnumerable<int> isn't an IEnumerable<object>)
Not unless you have a non-generic base-type ValuePair with ValuePair<T> : ValuePair (it would work for an interface too), or use List<object>. Actually, though, this works reasonably:
public abstract class ValuePair
{
public string Name { get; set; }
public object Value
{
get { return GetValue(); }
set { SetValue(value); }
}
protected abstract object GetValue();
protected abstract void SetValue(object value);
}
public class ValuePair<T> : ValuePair
{
protected override object GetValue() { return Value; }
protected override void SetValue(object value) { Value = (T)value; }
public new T Value { get; set; }
}
No, it is not possible. You could create, in your case, a base class ValuePair from which ValuePair<T> derives. Depends on your purposes.
it's not possible as far as I know.
the line:
List<ValuePair> list = new List<ValuePair>();
you wrote in your sample is not providing a concrete type for T and this is the issue, once you pass it, you can only add object of that specific type.
lately I started to learn generics. I run into trouble with storing references to generic classes instances. As you can see, my class ListHandler can store references to specific type of BaseClass. I would love to register BaseClass instances by themselves, which is why I wanted to guarantee that they will use BaseParamClass by adding 'where'. Anyway - it does not compile.'This', does not know that T is actually BaseClassParam even with 'where' keyword in class. I don't know what is wrong here and I couldn't find answer anywhere. I would be grateful for tips/guides/solutions.
public class ListHandler
{
private List<BaseClass<BaseParamClass>> list;
public ListHandler()
{
list = new List<BaseClass<BaseParamClass>>();
}
public void Register(BaseClass<BaseParamClass> param)
{
list.Add(param);
}
}
public class BaseClass<T> where T : BaseParamClass
{
private ListHandler listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this); //throws error
}
}
Why don't you make ListHandler generic as well?
public class ListHandler<T>
{
private List<BaseClass<T>> list;
public ListHandler()
{
list = new List<BaseClass<T>>();
}
public void Register(BaseClass<T> param)
{
list.Add(param);
}
}
public class BaseClass<T>
{
private ListHandler<T> listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler<T> listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
}
Also, it seems strange to me to have BaseClass<T> contain a reference to a class that has a reference to BaseClass<T> itself.
I have another option for you.
Let's split the BaseClass<T> class into two with a non-generic base, like so:
public class BaseClass
{
protected ListHandler listHandler;
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
}
}
public class BaseClass<T> : BaseClass where T : BaseParamClass
{
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
: base(listHandler)
{
listHandler.Register(this); // Compiles nicely! Yay!
}
}
Now, the list inside ListHandler can be defined as private List<BaseClass> list;. That means there is no problem adding any BaseClass item to the list. We also can then define two methods for registering and fetching generic versions of the BaseClass<T> from the ListHandler. It would look like this:
public class ListHandler
{
private List<BaseClass> list;
public ListHandler()
{
list = new List<BaseClass>();
}
public void Register<T>(BaseClass<T> param) where T : BaseParamClass
{
list.Add(param);
}
public BaseClass<T> Fetch<T>() where T : BaseParamClass
{
return list.Select(x => x as BaseClass<T>).Where(x => x != null).FirstOrDefault();
}
}
So, given a class public class FooParam : BaseParamClass { } I can write this code:
ListHandler listHandler = new ListHandler();
BaseClass<FooParam> baseClass = new BaseClass<FooParam>(listHandler);
BaseClass<FooParam> baseClass2 = listHandler.Fetch<FooParam>();
Console.WriteLine(object.ReferenceEquals(baseClass, baseClass2));
The result from this code is True is written to the console - which means I can successfully fetch the instance of BaseClass<FooParam> from the ListHandler.
Why your code doesn't compile
In order to fully understand why your code doesn't compile, you'll have to dive into covariance and contravariance, which is a big topic and hard to explain in an SO answer. It can be especially confusing if you've gotten to a point where inheritance polymorphism is second nature to you; the rules are just different enough to be make your head hurt.
Here is what is confusing--
You're used to doing this:
object a = new String(...);
But generics don't let you do this!
List<object> c = new List<string>(); //Compiler error
That's because those two Lists are not related the same way that object and string are related. One does not inherit from the other. Rather, they are different variants of a generic type definition. In the generic world, you can't assign one to the other. The same is true of this:
void Foo<T>() where T: BaseParamClass
{
BaseClass<BaseParamClass> a = new BaseClass<T>(); //Compiler error
}
In this example, T could be BaseParamClass or one of its derived types. They are not the same type. So to remain type-safe, the compiler has to disallow this assignment, and your Register call, which has the same type mismatch.
Standard ways around this
You need a covariant interface. These allow assignment from derived to base. So for example, while this is still illegal:
List<object> a = new List<string>(); //Compiler error
This is totally fine:
IEnumerable<object> e = new List<string>(); //Is OK
Because IEnumerable was declared to be covariant, like this:
interface IEnumerable<out T>
Which means it is can be assigned in this way. It works because using out also adds a compiler constraint to the interface: it can be used to retrieve stuff...
interface IEnumerable<out T>
{
T Item[int index];
}
...but it cannot accept anything:
interface IEnumerable<out T>
{
Add(T item); //Compiler error
}
These constraints are what allow generics to provide early-bound type safety while still allowing certain forms of (non-inheritance) polymorphism.
What I'd suggest
Based on your comment, it sounds like you just need a container (a stack, apparently) that can hold references to these BaseClass<T> instances. If you are following separation of concerns, the stack doesn't need to actually do anything with the T, other than store it and retrieve it, and to allow it to register itself.
Since that is a separate concern, make a separate interface.
And in the interest of keeping things simple, maybe avoid using generics completely for this bit.
One way to do it--
Create an interface that allows access to everything the stack needs to know about an item it is containing. For example, if the stack contains popups of various kinds, you may want to expose the popup's title.
interface IStackable
{
string Title { get; set; }
}
Now use it like this:
public class ListHandler
{
private readonly Dictionary<string, IStackable> list;
public ListHandler()
{
list = new Dictionary<string, IStackable>();
}
public void Register(IStackable item)
{
list.Add(item.Title, item);
}
}
public class BaseClass<T> : IStackable where T : BaseParamClass
{
private ListHandler listHandler;
public T Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
public string Title { get; set; }
}
Unless there is some other requirement, you shouldn't need to make it any more complicated than that.
All you really need to do is add an interface. This works:
public class BaseParamClass
{
}
public class ListHandler
{
private List<IBase<BaseParamClass>> list;
public ListHandler()
{
list = new List<IBase<BaseParamClass>>();
}
public void Register(IBase<BaseParamClass> param)
{
list.Add(param);
}
}
public interface IBase<T> where T : BaseParamClass
{
T Param {get; }
}
public class BaseClass : IBase<BaseParamClass>
{
private ListHandler listHandler;
public BaseParamClass Param { get; private set; }
public BaseClass(ListHandler listHandler)
{
this.listHandler = listHandler;
listHandler.Register(this);
}
}
Working code on DotNetFiddle
I wrote the following console app to test static properties:
using System;
namespace StaticPropertyTest
{
public abstract class BaseClass
{
public static int MyProperty { get; set; }
}
public class DerivedAlpha : BaseClass
{
}
public class DerivedBeta : BaseClass
{
}
class Program
{
static void Main(string[] args)
{
DerivedBeta.MyProperty = 7;
Console.WriteLine(DerivedAlpha.MyProperty); // outputs 7
}
}
}
As this console app demonstrates, the MyProperty property exists once for all instances of BaseClass. Is there a pattern to use which would allow me to define a static property which will have allocated storage for each sub-class type?
Given the above example, I would like all instances of DerivedAlpha to share the same static property, and all instances of DerivedBeta to share another instance of the static property.
Why am I trying to do this?
I am lazily initializing a collection of class property names with certain attributes (via reflection). The property names will be identical for each derived class instance, so it seems wasteful to store this in each class instance. I can't make it static in the base class, because different sub-classes will have different properties.
I don't want to replicate the code which populates the collection (via reflection) in each derived class. I know that one possible solution is to define the method to populate the collection in the base class, and call it from each derived class, but this is not the most elegant solution.
Update - Example of what I'm doing
At Jon's request, here's an example of what I'm trying to do. Basically, I can optionally decorate properties in my classes with the [SalesRelationship(SalesRelationshipRule.DoNotInclude)] attribute (there are other attributes, this is just a simplified example).
public class BaseEntity
{
// I want this property to be static but exist once per derived class.
public List<string> PropertiesWithDoNotInclude { get; set; }
public BaseEntity()
{
// Code here will populate PropertiesWithDoNotInclude with
// all properties in class marked with
// SalesRelationshipRule.DoNotInclude.
//
// I want this code to populate this property to run once per
// derived class type, and be stored statically but per class type.
}
}
public class FooEntity : BaseEntity
{
[SalesRelationship(SalesRelationshipRule.DoNotInclude)]
public int? Property_A { get; set; }
public int? Property_B { get; set; }
[SalesRelationship(SalesRelationshipRule.DoNotInclude)]
public int? Property_C { get; set; }
}
public class BarEntity : BaseEntity
{
public int? Property_D { get; set; }
[SalesRelationship(SalesRelationshipRule.DoNotInclude)]
public int? Property_E { get; set; }
public int? Property_F { get; set; }
}
Desired end result
Accessing FooEntity.PropertiesWithDoNotInclude returns a List<string> of:
{
"Property_A",
"Property_C"
}
Accessing BarEntity.PropertiesWithDoNotInclude returns a List<string> of:
{
"Property_E"
}
Two possible approaches:
Use attributes; decorate each subclass with an attribute, e.g.
[MyProperty(5)]
public class DerivedAlpha
{
}
[MyProperty(10)]
public class DerivedBeta
{
}
That only works when they're effectively constants, of course.
Use a dictionary:
var properties = new Dictionary<Type, int>
{
{ typeof(DerivedAlpha), 5) },
{ typeof(DerivedBeta), 10) },
};
EDIT: Now that we have more context, Ben's answer is a really good one, using the way that generics work in C#. It's like the dictionary example, but with laziness, thread-safety and simple global access all built in.
Jon has a good solution as usual, although I don't see what good attributes do here, since they have to be explicitly added to every subtype and they don't act like properties.
The Dictionary approach can definitely work. Here's another way to do that, which explicitly declares that there will be one variable per subclass of BaseEntity:
class FilteredProperties<T> where T : BaseEntity
{
static public List<string> Values { get; private set; }
// or static public readonly List<string> Values = new List<string>();
static FilteredProperties()
{
// logic to populate the list goes here
}
}
The drawback of this is that it's rather difficult to pair with a GetType() call such as you might use in methods of BaseEntity. A Dictionary, or wrapper thereto which implements lazy population, is better for that usage.
I just recently needed this same thing and came across this question. I think Jon's and Fried's ideas to use a Dictionary are on the right track but don't quite hit what I was looking for so I thought I'd show my own complete and very easy to extend implementation.
public class TypeStaticProperty<T>
{
T _defaultValue;
Dictionary<Type, T> _values = new Dictionary<Type, T>();
public TypeStaticProperty(T defalutValue = default)
{
_defaultValue = defalutValue;
}
public T Get(object caller)
{
lock (_values)
{
if (_values.TryGetValue(caller?.GetType(), out T val))
return val;
else
return _defaultValue;
}
}
public void Set(object caller, T val)
{
lock (_values)
_values[caller?.GetType()] = val;
}
}
And to demonstrate:
class TestBaseClass
{
static TypeStaticProperty<int> _property = new TypeStaticProperty<int>();
public int Property
{
get => _property.Get(this);
set => _property.Set(this, value);
}
}
class TestClass1 : TestBaseClass
{
}
class TestClass2 : TestBaseClass
{
}
class Program
{
static void Main(string[] args)
{
TestClass1 test1a = new TestClass1();
TestClass1 test1b = new TestClass1();
test1a.Property = 1;
test1b.Property = 2;
TestClass2 test2a = new TestClass2();
TestClass2 test2b = new TestClass2();
test2a.Property = 3;
test2b.Property = 4;
Console.WriteLine($"test1a.Property = {test1a.Property}");
Console.WriteLine($"test1b.Property = {test1b.Property}");
Console.WriteLine($"test2a.Property = {test2a.Property}");
Console.WriteLine($"test2b.Property = {test2b.Property}");
}
}
Output:
test1a.Property = 2
test1b.Property = 2
test2a.Property = 4
test2b.Property = 4
So while you still need a class instance to access and set the property, the value will always be the same across all instances of that precise type. (This includes generics too; Foo<int> will be seen as a different type than Foo<string>). This has the huge advantage over Fried's example in that you don't need to know at compile time the precise type whose "static" value you're looking for when accessing or setting.
PS - For full disclosure, this was heavily inspired by the WPF source code, which uses a very similar pattern for DependencyProperty's and all kinds of other internal bells and whistles designed to improve performance and reduce memory footprint.
I have a helper class that does a simple but repetitive process on a List of entities. For simplicity, it's like this...
public static List<MyType> DoSomethingSimple(List<MyType> myTypes) {
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
I now need to add support for another type, but everything is identical... how do I avoid an increasing list of overloaded methods like this:
public static List<MyType> DoSomethingSimple(List<MyType> myTypes) {
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
public static List<MyOtherType> DoSomethingSimple(List<MyOtherType> myOtherTypes) {
return myOtherTypes.Where(myOtherType => myOtherType.SomeProperty.Equals(2)).ToList();
}
... and so on.
Here's two ways:
Use generics, and a common base class
Use interfaces
Method 1:
public class BaseClass
{
public int SomeProperty { get; set; }
}
public class MyType : BaseClass { }
public class MyOtherType : BaseClass { }
public class ClassWithMethod
{
public static List<T> DoSomethingSimple<T>(List<T> myTypes)
where T : BaseClass
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Method 2:
public interface ICommon
{
int SomeProperty { get; set; }
}
public class MyType : ICommon
{
public int SomeProperty { get; set; }
}
public class MyOtherType : ICommon
{
public int SomeProperty { get; set; }
}
public class ClassWithMethod
{
public static List<T> DoSomethingSimple<T>(List<T> myTypes)
where T : ICommon
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Now, if you try to make the method use the interface directly, like this:
public class ClassWithMethod
{
public static List<ICommon> DoSomethingSimple(List<ICommon> myTypes)
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Then that would work if you have a List<ICommon> when you call it, but won't work if you have a List<MyType>. In C# 4.0 this can be done if we change the method slightly:
public class ClassWithMethod
{
public static List<ICommon> DoSomethingSimple(IEnumerable<ICommon> myTypes)
{
return myTypes.Where(myType => myType.SomeProperty.Equals(2)).ToList();
}
}
Note that I changed to using an IEnumerable<ICommon> instead. The concept here is called Co- and contra-variance, and beyond that I'm not going to say much about it. Search Stack Overflow for more information on the subject.
Tip: I would change the input parameter to be IEnumerable<T> regardless, since this would make your method usable in more instances, you could have different types of collections, arrays, etc. and as long as they contain the right type, they can be passed to the method. By limiting yourself to List<T> you force the user of your code to convert to a list in some cases. My guidelines are to be as unspecific as possible in input parameters, and as specific as possible in output parameters.
Assuming the property has the same name and type for each list type, you could add an interface containing the property and implement it for each type you want to call this method on:
public interface ISomeProperty
{
object SomeProperty { get; }
}
DoSomethingSimple could then be:
public static List<T> DoSomethingSimple<T>(IEnumerable<T> list) where T : ISomeProperty
{
return list.Where(i => i.SomeProperty.Equals(2)).ToList();
}