How to cast when chaining methods in C# - c#

I'm trying to code something, and I always return the object itself so I can keep chaining. Like this
object.SetThis().SetThat().SetThisThirdThing().setThisFourthThing();
I return this in all my methods so I can keep doing this. But one of my methods is something I made in my base class, which of course then returns the base class.
So instead of public MyClass SetThat() it returns public SuperClass SetThat(). And because it returns SuperClass and not MyClass I can't call SetThisThirdThing() because the base class doesn't know about it.
So how do I cast it so I can keep the chain? What is the syntax? I tried
object.SetThis().(MyClass)SetThat().SetThisThirdThing().setThisFourthThing();
Or is there a way to make a superClass method return the subclass when called from the subclass without having to override it in all the subclasses?
This is one of the things that all the subclasses have in common, so it would be really nice if I would be able to circumvent this somehow without having to override it in all my subclasses.

is there a way to make a superClass method return the subclass when called from the subclass without having to override it in all the subclasses?
Can you make the superclass generic?
public class SuperClass<T> where T: SuperClass<T>
{
public T SetThis()
{
....
return (T)this;
}
}
public class SubClass : SuperClass<SubClass>
{
}
Note that it's not 100% guaranteed since you could also do this:
public class EvilSubClass : SuperClass<SubClass>
{
}
which fits the generic contraints, but now the return type of SetThis() is SubClass and not EvilSubClass

var obj = ((MyType)myObject.SetThis()).SetThat();
P.S You should avoid doing that, since it can become quite confusing to read.

To cast a (sub)expression, you need to put the class name in front (and use parentheses).
((MyClass)obj.SetThis().SetThat()).SetThisThirdThing().setThisFourthThing();
(note that object is a reserved word, so you can't use it as a variable name)
An alternative is to use the as keyword:
(obj.SetThis().setThat() as MyClass).SetThisThirdThing().setThisFourthThing();
Note that this will behave differently if setThat() doesn't return a MyClass;
the first version will throw an InvalidCastException, the second version a NullReferenceException because as returns null if the cast is not possible.

Try like this:
((MyClass)object.SetThis().SetThat()).SetThisThirdThing()

Just use parenthesis:
(MyClass)(object.SetThis().SetThat()).SetThisThirdThing().setThisFourthThing();
I don't know why the object is there, but you can safely remove it.
(MyClass)(SetThis().SetThat()).SetThisThirdThing().setThisFourthThing();

Without modifying your classes, you can also write an extension method As like this
public static T As<T>(this MyBaseClass obj) where T : MyBaseClass
{
return (T)obj;
}
--
Usage would be similar to this
new MyChildClass().SetBase().As<MyChildClass>().SetThis();

Why not do it like this? A simple Cast method to help you cast it back to the correct type...
class Program
{
static void Main(string[] args)
{
var obj = new MyClass();
//obj.SetThis().SetThat().SetThisThirdThing().setThisFourthThing(); // Compile error
obj.SetThis().SetThat().Cast<MyClass>().SetThisThirdThing().setThisFourthThing();
}
}
class SuperClass
{
public SuperClass SetThat()
{
return this;
}
public T Cast<T>() where T : SuperClass
{
return (T)this;
}
}
class MyClass : SuperClass
{
public MyClass SetThis()
{
return this;
}
public MyClass SetThisThirdThing()
{
return this;
}
public MyClass setThisFourthThing()
{
return this;
}
}

Related

Restrict passing instances of derived classes as method parameters

Here's the situation. I have a class and a derived class
public class MyClass
{ }
public class MyDerivedClass : MyClass
{ }
And also I have a method (in an external class) which takes an instance of MyClass as a parameter:
public class AnotherClass {
public void DoSomething(MyClass myClass)
{ }
}
How can I restrict DoSomething method to accept instances of MyClass only, but not instances of MyDerivedClass?
If that's what you want then you would need to check in code yourself that if it is a Derived type through Exception to tell the calling code that Derived type objects are not allowed for this method:
public class AnotherClass {
public void DoSomething(MyClass myClass)
{
if(myClass.GetType() != typeof(MyClass))
{
throw new Exception("Derived objects not allowed");
}
}
}
What are you trying to do here is more related to an Invariance problem that is pretty common on all programming languages.
Means that you can use only the type originally specified; so an
invariant generic type parameter is neither covariant nor
contravariant. You cannot assign an instance of IEnumerable
(IEnumerable) to a variable of type
IEnumerable or vice versa.
Here is the reference for you https://msdn.microsoft.com/en-us/library/dd799517(v=vs.110).aspx
My advice, try to change the implementation and put all the methods into an interface, that should be more clear
class Root: Interface
{
...implementation of your common methods
}
class Derived: Interface
{
...implementation of your common methods
//this should just
public void DoSomething(MyClass myClass)
}
If you don't want to use the above approach then use the "as" operator to treat the parameter that you are passing as MyRootClass, var a = parameter as MyRootClass. If a is null then you are not passing the correct value to the method, or check for the type directly.
If would recommend that you read this topics:
http://amapplease.blogspot.com/2009/04/invariance-covariance-contravariance.html
https://stackoverflow.com/a/13107168/819153
https://blogs.msdn.microsoft.com/ericlippert/2009/03/19/representation-and-identity/
Hope this helps

Returning child type in Parent class

public abstract class Base
{
public Base ClassReturn()
{
return this;
}
}
Is there possibility to return child type that invoked ClassReturn method?
I've done that in extension method:
public static T ClassReturn<T>(this T obj) where T : Base
{
return (T) obj.ClassReturn();
}
But I want to embeed it in Base class instead of extension method. Is there possibility to do that with generics?
I will copy my comment which describes what I want to achieve:
I need something similiar to builder pattern and I have different
classes that depending on previous operations do something else, now I
want to have a similiar functionality in every of them and when I use
it I lose object type. So my solution is either implement that
functionality multiple times in every class or create extension
method. But I always thought when it is possible to make extension
method for class then I can embeed that in class, but as I see it is
not possible.
Full example:
public class Child1 : Base
{
public Child1 Operation1()
{
Console.WriteLine("operation1");
return this;
}
}
public class Child2 : Base
{
public Child2 Operation2()
{
Console.WriteLine("operation2");
return this;
}
}
static void Main(string[] args)
{
Child1 ch = new Child1();
ch.Operation1().Operation1().ClassReturn().Operation1()
}
I can't use Operation1 after ClassReturn if I don't use extension method.
Try this one:
public abstract class Base<T> where T: Base<T>
{
public T ClassReturn
{
get { return (T)this; }
}
}
public class Child1 : Base<Child1>
{
}
public class Child2 : Base<Child2>
{
}
From your question and your comments, what you are trying to achieve is not possible directly from the type system. By returning an instance of Base you are specifically saying that all you are interested is that you have something that derives from Base, but that the specific class doesn't matter. Statically, the compiler no longer has the information it needs to perform a cast.
If you are trying to get the original type back statically, then you have to supply the information to the compiler, and in this case you can't guarantee that you have the correct information. In the example below, the instance is created from derived type A but attempted to be cast to derived type B through the extension, the compiler will allow the code to compile, but you'll get an exception at runtime.
public class A : Base { }
public class B : Base { }
public static class BaseExtensions
{
public static T GetAsT<T>(this Base base) where T: Base
{
return (T)base;
}
}
public static void Main()
{
Base obj = new A();
B b = obj.BaseAsT<B>(); // This compiles but causes an exception
}
You should look up the Liscov Substitution Principle to get information on how to properly work with base and derived classes in the system as a whole, and then write up a question dealing specifically with the result you are trying to achieve.

public T GetMyClass<T>() where T : MyClass, new() { /* is this pointless? */ }

are the two methods in the class "Confused" below the same?
class MyClass
{
public override string ToString()
{
return "I am confused now";
}
}
class Confused
{
public MyClass GetMyClass()
{
return new MyClass();
}
public T GetMyClass<T>() where T : MyClass, new()
{
return System.Activator.CreateInstance<T>();
}
}
class Program
{
static void Main()
{
Confused c = new Confused();
System.Console.WriteLine(c.GetMyClass());
System.Console.WriteLine(c.GetMyClass<MyClass>());
}
}
They produce different IL, but is there any reason to write the generic version other than the 'straight up' version other than to confuse the heck out of collegues :)
If you write the generic version, you can instantiate and return derived classes:
where T : MyClass
Also, with the generic version you don't need the activation code:
return new T();
This is because you have specified:
where T : new()
The generic constraint enforcing a public parameterless constructor.
Sure there's a difference. Let's say you have a second class deriving from MyClass:
class MyClass2 : MyClass { }
Then you can do
MyClass2 myClass2 = confused.GetMyClass<MyClass2>();
You can't do that with the other function.
MyClass could be a base class (or an interface IMyClass). The generic version with the constraint says you want this function to work for any class derived from (or implementing) a common base or interface and to return the result as that derived class, not as the base.
class MyClass { }
class MySpecializedClass : MyClass { }
// etc.
There is a very big difference:
The non generic version can only return instances of type MyClass, whereas the generic version can return instances of type MyClass and all classes derived from MyClass!
No. They are not the same. The first will only ever construct a MyClass object, and the second will construct any object that is a MyClass or a descendent of MyClass, based on the type parameter.
They would give the same result ONLY if you called .GetMyClass<MyClass>(). However, I presume the extra method has been created to allow for creation of other classes? If not, then they're the same, so one's redundant (and I'd get rid of the generic version as has overhead inside the assembly).
Are they being used differently?
They are not the same. The generic allows inherited classes to be built as well like this:
class MyClass
{
public override string ToString()
{
return "I am confused now";
}
}
class InheritedClass : MyClass
{
}
class Confused
{
public MyClass GetMyClass()
{
return new MyClass();
}
public T GetMyClass<T>() where T : MyClass, new()
{
return System.Activator.CreateInstance<T>();
}
}
class Program
{
static void Main()
{
Confused c = new Confused();
System.Console.WriteLine(c.GetMyClass());
System.Console.WriteLine(c.GetMyClass<MyClass>());
System.Console.WriteLine(c.GetMyClass<InheritedClass>());
}
}
I'm not quite sure, but Generics are a runtime feature in .NET. Therefore, the non-generic method isn't equivalent to the generic one, even though it is used equivalently. As they're public, this can't be optimized away.

Why Is It That Generics Constraint Can't Be Casted to Its Derived Type?

It is quite puzzling to find out that Generics Constraint Can't Be Casted to Its Derived Type.
Let's say I have the following code:
public abstract class BaseClass
{
public int Version
{ get { return 1; } }
public string FixString { get; set; }
public BaseClass()
{
FixString = "hello";
}
public virtual int GetBaseVersion()
{
return Version;
}
}
public class DeriveClass: BaseClass
{
public new int Version
{ get { return 2; } }
}
And guess what, this method will return a compilation error:
public void FreeConversion<T>(T baseClass)
{
if(baseClass.GetType()==typeof(DeriveClass)
var derivedMe = (DeriveClass)baseClass;
}
I would have to cast the baseClass to object first before I can cast it to DerivedClass, i.e.,
public void FreeConversion<T>(T baseClass)
{
if(baseClass.GetType()==typeof(DeriveClass)
var derivedMe = (DeriveClass)((object)baseClass);
}
Seems to me pretty ugly. Why this is so?
First, you shouldn't be casting a base type variable to a derived type. It's not supposed to work, only the other way around.
Second, why it works via object, is because you remove the compile-time type checks. The compiler can check that a BaseType cannot be cast to DerivedType. But when a variable is object, the compiler leaves it assuming you know what you're doing. Even if it will compile, the code will then crash during execution.
The answer is simple: the compiler can't know that T in your FreeConversion method can be converted to DeriveClass.
As you already stated, the cheap trick is to first cast to object, then to the type you want to go. Ugly, but it works.
Apart from that, it may be that you are violating Liskov Substitution principle, nothing that will harm any animals but can drive your design towards unmaintainable code.
Third, a nice trick to let your base class expose the derived type is something like this:
public class Base<T> where T : Base<T> {
T IAmDerived;
}
public class Derived : Base<Derived> { }
First of all, in your generic method the type T could be a vale type or reference type. And the reason why it allows you to do via 'Object' is that, you're simply doing boxing-unboxing which works for any type in system.
Secondly.it will be a terrible idea to convert/cast a baseclass object into a derived class. You're violating the mechanics of OOP.
If you really want to return an object of type derived from the base class, here's one way possible - the solution is pretty much similar to what Frank has offered.
//This is how you create a function in BaseClass that returns the collection
//of DerivedTypes when called from an object of type derivedclass, no magic just Generics.
//**The BaseClass**
public class BaseClass<T>
where T : BaseClass<T>
{
public HashSet<T> GetHashSet()
{
HashSet<T> _hSet = new HashSet<T>();
//do some work
//create a HashSet<T> and return;
return _hSet;
}
}
//**The Derived Class**
public class DerivedClass : BaseClass<DerivedClass>
{
//you have the method inherited.
}

How to return generic abstract class?

I have something like this:
abstract class BaseClass<T>
{
protected BaseClass(){}
}
class Class1 : BaseClass<Class1>
{
public static Class1 Instance = new Class1();
private Class1(){}
}
class Class2 : BaseClass<Class2>
{
public static Class2 Instance = new Class2();
private Class2(){}
}
...
public BaseClass<T> Method<T>(int z) where T: BaseClass<T>
{
switch(z)
{
case 1:
return Class1.Instance;
case 2:
return Class2.Instance;
}
}
That is very important that those classes cannot be instantiated since their construstors are private so we cannot do like
public BaseClass<T> Method<T>(int z) where T: BaseClass<T>, new()
How can I use abstract class as return type ?? I just can not work this out. Would appreciate for any assisstance here.
It sounds to me like you can't really have the method be generic. For instance, what would happen if I called:
BaseClass<Class1> foo = Method<Class1>(2);
You need a single point of truth - either the type argument, or the normal argument. You can make it the method argument by having a non-generic base class (either by making the existing base class non-generic, or introducing a non-generic base class to that). Change the return type of Method to this non-generic base class.
abstract class BaseClass<T>
{
public abstract T Instance { get; }
protected BaseClass(){}
}
maybe? You can't inherit static stuff I believe...
On a closer look... I don't think what you are trying to do is even possible... what are you trying to do anyways?
A type constraint is a type constraint. You are trying to change the type constraint in the method kind of. which obviously doesn't work, and shouldn't work. I think you need to think of a different way of attacking your problem. Whatever it is...
Take a look at the factory pattern. Your factory can have a method on it to get the instance. The first time it's called, it creates the instance. On subsequent calls, it can return the already-created instance.

Categories

Resources