I am trying to create something very similar to how EF Core uses builders in their entity configuration (e.g., IEntityTypeConfiguration<TEntity>, EntityTypeBuilder<TEntity>, PropertyBuilder<TEntity>).
In the below code, I would like the ObjectBuilder<> class and SubObject() method to infer the type from the class they are implemented in (in this case, MyClass). Is this possible?
It would also be great if I could infer the second type from the interface being implemented (the SomeType type), but I am pretty sure this is not possible.
It may be that I need a completely different approach to this, but I have yet to come up with an alternate solution.
Thank you for the help.
public interface ISomeInterface<T2> { }
public class SomeType
{
public string MySubObjectField { get; }
public string MySubObjectField2 { get; }
}
public class MyClass : ISomeInterface<SomeType>
{
public string MyObjectField { get; }
public string MyObjectField2 { get; }
public MyClass()
{
ObjectBuilder<MyClass, SomeType> builder = new ObjectBuilder<MyClass, SomeType>();
builder
.SubObject<MyClass>(c => c.MyObjectField)
.HasSomething(t => t.MySubObjectField)
.IsSomething();
builder
.SubObject<MyClass>(c => c.MyObjectField2)
.HasSomething(t => t.MySubObjectField2);
}
}
public class ObjectBuilder<T1, T2>
{
public SubObjectBuilder<T2> SubObject<T1>(Expression<Func<T1, object>> expression)
{
// Simplified for question
return new SubObjectBuilder<T2>();
}
}
public class SubObjectBuilder<T2>
{
public SubObjectBuilder<T2> HasSomething(Expression<Func<T2, object>> expression)
{
// Do something
return this;
}
public SubObjectBuilder<T2> IsSomething()
{
// Do something
return this;
}
}
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);
}
}
}
Given the following classes (factories used because C# doesn't support type inference on constructors):
public class A<T>
{
public A(B<T> b) { }
}
public class B<T>
{
public B(C<T> c) { }
}
public class C<T>
{
public C(T tee) { }
}
public class D<T>
{
public static D<T> Create<V>(Expression<Func<T, V>> property)
{
return new D<T, V>(property);
}
}
public class D<T, V> : D<T>
{
public D(Expression<Func<T, V>> property) { }
}
public class Model
{
public int P1 { get; set; }
public string P2 { get; set; }
}
public class AFactory
{
public static A<T> Create<T>(B<T> bee)
{
return new A<T>(bee);
}
}
public class BFactory
{
public static B<T> Create<T>(C<T> cee)
{
return new B<T>(cee);
}
}
public class CFactory
{
public static C<T> Create<T>(params D<T>[] tees)
{
return null;
}
}
The following compiles:
AFactory.Create(BFactory.Create(CFactory.Create(
D<Model>.Create(m => m.P1), D<Model>.Create(m => m.P2)
)));
The following does not:
AFactory.Create<Model>(BFactory.Create(CFactory.Create(
D.Create(m => m.P1), D.Create(m => m.P2)
)));
The difference is that in the first example I'm specifying the type of the model on the innermost classes, so type inference works normally and propagates up the tree. The problem is that I then have to specify the model type on every D.Create() call, which seems redundant.
The second example is the way I'd like to write this code: tell the outermost class that its type is Model and all the classes that are being constructed use that type as well. Essentially, it's syntactic sugar for AFactory.Create<Model>(BFactory.Create<Model>(/* turtles all the way down... */)).
Is there any way to achieve this in C#? I've tried all the permutations of inheritance and type constraints that I can think of, but nothing has given me the desired result.
I'm also fully aware that I might be missing something fundamental about generics - please feel free to educate me if that's the case.
I've got a minimal interface, and will be dealing with a collection of objects whose classes implement this interface. The collection (along with its associated functionality) doesn't care about any of the details of these objects beyond their name, the ability to convert them to XML, and the ability to parse them from XML.
Future implementations of the interface will do a lot more with the elements of the collection, and will obviously implement their own Parse and ToXml methods (which will be used by the collection to parse these items appropriately when encountered).
Unfortunately, I am unable to list a static Parse method in the interface (I've read these three questions). It doesn't make sense to me to have a Parse method require an instance. Is there any way to require that all implementations of the interface have a static Parse method?
public interface IFoo
{
string Name { get; }
string ToXml();
static IFoo Parse(string xml); // Not allowed - any alternatives?
}
You can't do that. And static methods aren't polymorphic anyway, so it wouldn't make too much sense.
What you want here is some kind of factory pattern.
Assuming Parse takes a string and turns it into a fully-populated object, how about a Hydrate method instead, like:
interface IFoo {
string Name { get; set; }
int Age { get; set; }
void Hydrate(string xml);
}
class Foo : IFoo {
public string Name { get; set; }
public int Age { get; set; }
public void Hydrate(string xml) {
var xmlReader = ...etc...;
Name = xmlReader.Read(...whatever...);
...etc...;
Age = xmlReader.Read(...whatever...);
}
}
void Main() {
IFoo f = new Foo();
f.Hydrate(someXml);
}
Or Fluent it up a bit:
public IFoo Hydrate(string xml) {
// do the same stuff
return this;
}
void Main() {
IFoo f = new Foo().Hydrate(someXml);
}
The only alternative that comes to my mind is to use an abstract class instead of an interface here. However you won't be able to override static method's behaviour in child classes anyway.
You can achieve somewhat similar behaviour using Factory pattern and requiring classes implementing IFoo to have a reference to that Factory (which can be injected in them via constructor injection):
public interface IFoo
{
string Name { get; }
string ToXml();
IFooFactory FooFactory { get; }
}
public interface IFooFactory
{
IFoo Parse(string xml);
}
I would extract all serialization-related methods into a different interface. Please consider the following example:
public interface IFoo
{
string Name { get; }
IFooSerializer GetSerializer(string format);
}
public enum FooSerializerFormat { Xml, Json };
public interface IFooSerializer
{
string Serialize(IFoo foo);
IFoo Deserialize(string xml);
}
public class Foo : IFoo
{
public string Name { get; }
public IFooSerializer GetSerializer(FooSerializerFormat format)
{
case FooSerializerFormat.Xml:
return new FooXmlSerializer();
case FooSerializerFormat.Json:
return new FooJsonSerializer();
}
}
public class FooXmlSerializer : IFooSerializer { /* Code omitted. */ }
public class FooJsonSerializer : IFooSerializer { /* Code omitted. */ }
Maybe this way?
public interface IFoo
{
string Name { get; }
string ToXml();
IFoo Parse(string xml);
}
public abstract class AFoo : IFoo
{
public string Name { get; set; }
public string ToXml() { };
public IFoo Parse(string xml) { return AFoo.StaticParse(xml); };
public static IFoo StaticParse(string xml) { }; // implement one here
}
Even if the above could be a solution I would encourage you to use the abstact factory and/or template method instead. See Template Method Pattern instead. Another Option might be the usage of an Extension method if you wan't to share it among several implementations.
Broadly speaking, I have been known (on occasion) to use Extension methods for stuff like this:
public interface IFoo
{
string Name {get;}
string ToXml();
}
public class Foo : IFoo
{
public Foo(string name)
{
Name = name;
}
public string Name {get; private set;}
public string ToXml()
{
return "<derp/>";
}
}
So that's the instance stuff, let's handle the "static" bit:
public static class FooExts
{
public static IFoo Parse(this string xml)
{
return new Foo("derp");
}
}
And a test:
void Main()
{
var aFoo = "some xml".Parse();
Console.WriteLine(aFoo.ToXml());
}
As #Jim mentions, there is the case where you don't want a Foo back, in which case you might use something like:
public static T Parse<T>(
this string xml,
Func<string, IFoo> useMeUseMe = null)
where T:IFoo
{
if(useMeUseMe == null)
useMeUseMe = (x => new Foo(x));
return (T)useMeUseMe("derp");
}
Alas, we must now tell the method what we want when we deviate from the "norm":
var aFoo = "some xml".Parse<Foo>();
Console.WriteLine(aFoo.ToXml());
var aBar = "some xml".Parse<Bar>(s => new Bar(s));
Console.WriteLine(aBar.ToXml());
I have a need to create a couple of classes that will serve as base classes for some data functionality I want to implement.
The first, we'll call SessionObjectDataItem looks like this ...
public class ObjectSessionDataItem
{
public int ID { get; set; }
public bool IsDirty { get; set; }
public bool IsNew { get; set; }
public bool IsRemoved { get; set; }
}
And next I want a List called ObjectSessionDataList and this is where I get stuck.
I can create the class OK ...
public class SessionObjectDataList<SessionObjectDataItem> : List<SessionObjectDataItem>
{
}
where I fall down is trying to define properties on the list that access items in it. For example, I want to write...
public List<SessionObjectDataItem> DirtyItems
{
get
{
return this.Where(d => d.IsDirty).ToList();
}
}
but VS refuses to recognise the SessionObjectDataItem property IsDirty inside the List object definition.
What I'm trying to end up with is a case where I might define
public class AssociatedDocument : SessionObjectDataItem
{
...
}
public class DocumentList : SessionObjectDataList
{
}
And then be able to say...
DocumentList list = new DocumentList();
...
foreach(AssociatedDocument doc in list.DirtyItems)
{
...
}
Can I actually do what it is that I'm attempting? Am I just doing it wrong?
Generic constraints will help here; you can write a container-class for which the generic type-parameter is constrained to be SessionObjectDataItem or one of its subtypes. This will allow you to construct a generic class that can hold instances of a specific sub-type of SessionObjectDataItem.
public class SessionObjectDataList<T> : List<T> where T : SessionObjectDataItem
{
public SessionObjectDataList<T> DirtyItems
{
get
{
return this.Where(d => d.IsDirty).ToList();
}
}
}
Usage:
var list = new SessionObjectDataList<AssociatedDocument>();
...
foreach(AssociatedDocument doc in list.DirtyItems)
{
...
}
Try to use the generic version Where<T> of the queryable interface:
public List<SessionObjectDataItem> DirtyItems
{
get
{
return this.AsQueryAble().Where<SessionObjectDataItem>(d => d.IsDirty).ToList();
}
}
Else Where simply assumes d as type Object.
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();
}