I have 3 classes:
class O
{
}
class A : O
{
}
class B : A
{
}
When I call my code:
List<O> myList = new List<O>();
myList.Add(new A());
myList.Add(new B());
foreach (O obj in myList)
{
if (obj is A)
{
// do something
}
else if (obj is B)
{
//do something
}
}
However I realized that if (obj is A) will be evaluated to be true even when my obj is of class B. Is there a way to write the statement such that it evaluates to true if and only if obj is of class B?
Why don't you define a virtual function in the base class and override it in the derived types, doing what you need in the different cases?
class O {
public virtual void DoSomething() {
// do smtgh in the 'O' case
}
}
class A : O {
public override void DoSomething() {
// do smtgh in the 'A' case
}
}
class B : A {
public override void DoSomething() {
// do smtgh in the 'B' case
}
}
Then your loop becomes
foreach (O obj in myList) {
obj.DoSomething();
}
There are two method GetType and typeof
GetType is a method on object. It provides a Type object, one that
indicates the most derived type of the object instance.
and
Typeof returns Type objects. It is often used as a parameter or as a
variable or field. The typeof operator is part of an expression that
acquires the Type pointer for a class or value type
Try like this
if(obj.GetType() == typeof(A)) // do something
else if(obj.GetType() == typeof(B)) //do something
Related
ClassA, ClassB, ClassC and ClassD are all implementing IMyClass interface.
myObj is an instance of one of the classes.
private void setObj<T>()
{
myObj = mycollection.Single(w => w is T);
}
public void Switch()
{
if(myObj is ClassA)
{
setObj<ClassA>();
}
else if(myObj is ClassB)
{
setObj<ClassB>();
}
else if(myObj is ClassC)
{
setObj<ClassC>();
}
else if(myObj is ClassD)
{
setObj<ClassD>();
}
}
How can we refactor the Switch method, so that I have something like this:
public void Switch()
{
// How can we know from `myObj`, which class it is and rewrite
// the whole Switch method like this
// X = `ClassA`, `ClassB`, `ClassC` or `ClassD`
setObj<X>();
}
You cannot pass a generics type parameter as a variable in C#. However, you can get the type via reflection (myObj.GetType()) and pass that as a function parameter from your Switch() function to your setObj() function, which in turn can be compared in your lambda:
private void setObj(Type type)
{
myObj = Objects.Single(o => o.GetType() == type);
}
public void Switch()
{
Type setToThisType = myObj.GetType();
setObj(setToThisType);
}
make Switch a generic method too that accepts an object of type T
public void Switch<T>(T obj) where T : IMyClass
{
setObj<T>();
}
The where T : IMyClass statement ensures that you can only call Switch where obj is an instance of a class implementing IMyClass
void Example()
{
ClassA objA = new ClassA();
Switch(objA); //OK;
ClassX objX = new ClassX();
Switch(objX); //compile-time error since ClassX doesn't implement IMyClass
}
EDIT: after reading the title, I think you would need to have the parameter T obj in the Switch method.
Try using typeof(ClassA)
public void TypeTest(Type t)
{
if(t.Equals(typeof(ClassA))){
}
}
I have an Author object (extends IModel) that is sent to a generic method:
IModel author = new Author() { ... };
(new Base).Method(author);
and the Base class method:
public void Method<T>(T obj) where T : IModel {
//does stuff
AddToList(obj);
}
private void AddToList<T>(T obj) where T : IModel {
if(obj is Author)
{
var temp = (Author)obj; // <-- this is where the error comes up
//does stuff
}
else if(obj is SomethingElse)
//...
}
How can I cast back from a generic type (T) back to the main Type (Author or anything else that the typeof matches?
Try replacing the line with obj as Auther. It should work.
From https://msdn.microsoft.com/en-us/library/aa479858.aspx
Looks like you need a temporary object first.
class MyOtherClass
{...}
class MyClass<T>
{
void SomeMethod(T t)
{
object temp = t;
MyOtherClass obj = (MyOtherClass)temp;
}
}
I'm looking at a function with this pattern:
if( obj is SpecificClass1 )
{
((SpecificClass1)obj).SomeMethod1();
}
else if( obj is SpecificClass2 )
{
((SpecificClass2)obj).SomeMethod2();
}
else if( obj is SpecificClass3 )
{
((SpecificClass3)obj).SomeMethod3();
}
and get a code analysis warning: CA1800 Do not cast unnecessarily.
What's a good code pattern I can use to replace this code with that will be performant and concise.
Update
I didn't say, but obj is declared with type object.
I originally asked two questions here. I've split one off (which nobody had yet answered anyway): Why wouldn't the compiler optimize these two casts into one?
Interface
The best way would be to introduce an interface that all the types implement. This is only possible if the signatures match (or you don't have too many differences).
Using as
If creating an interface is not an option, you can get rid of the CA message by using the following pattern (though this also introduces unnecessary casts and therefore degrades performance a bit):
var specClass1 = obj as SpecificClass1;
var specClass2 = obj as SpecificClass2;
var specClass3 = obj as SpecificClass3;
if(specClass1 != null)
specClass1.SomeMethod1();
else if(specClass2 != null)
specClass2.SomeMethod2();
else if(specClass3 != null)
specClass3.SomeMethod3();
You can also change it to this structure (from my point of view, the above is better in terms of readability):
var specClass1 = obj as SpecificClass1;
if (specClass1 != null)
specClass1.SomeMethod1();
else
{
var specClass2 = obj as SpecificClass2;
if (specClass2 != null)
specClass2.SomeMethod2();
else
{
var specClass3 = obj as SpecificClass3;
if (specClass3 != null)
specClass3.SomeMethod3();
}
}
Registering the types in a dictionary
Also, if you have many types that you want to check for, you can register them in a dictionary and check against the entries of the dictionary:
var methodRegistrations = new Dictionary<Type, Action<object> act>();
methodRegistrations.Add(typeof(SpecificClass1), x => ((SpecificClass1)x).SomeMethod1());
methodRegistrations.Add(typeof(SpecificClass2), x => ((SpecificClass2)x).SomeMethod2());
methodRegistrations.Add(typeof(SpecificClass3), x => ((SpecificClass3)x).SomeMethod3());
var registrationKey = (from x in methodRegistrations.Keys
where x.IsAssignableFrom(obj.GetType()).FirstOrDefault();
if (registrationKey != null)
{
var act = methodRegistrations[registrationKey];
act(obj);
}
Please note that the registrations are easily extendable and that you can also call methods with different arguments in the action.
To avoid the double casting you could do the following
var objClass1= obj as SpecificClass1;
if(objClass1!=null)
objClass1.SomeMethod1();
Regarding the pattern you could make all these classes implement a common interface and make your method receive the interface.
public void SomeMethod(ISpecificInterface specific)
{
specific.SomeMethod1();
}
Can you do something like this here?
interface IBaseInterface
{
void SomeMethod();
}
public class Implementer1:IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
public class Implementer2 : IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
public class Implementer3 : IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
And then, in caller code:
IBaseInterface concrete = GetInstance();
concrete.SomeMethod();
and GetInstance would create class objects based on conditions.
Your classes can be inherite a ISomeMethodInterface like this:
public interface ISomeMethodInterface
{
void SomeMethod();
}
public class SpecificClass1 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
public class SpecificClass2 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
public class SpecificClass3 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
And in your call:
((ISomeMethodsInterface)obj).SomeMethod();
The most extensible solution would probably be inheriting the concrete class while implementing an interface with a SomeMethod implementation that calls the correct SomeMethodx method on the inherited class. That way, you'll keep the existing interface while still keeping the existing methods.
public interface ISomething {
void SomeMethod();
}
public SpecificClass1Wrapper : SpecificClass1, ISomething {
void SomeMethod() { SomeMethod1(); }
}
If the objects are wrapped in this way before they're stored in the object reference, a cast to ISomething and a call to SomeMethod() will replace your entire if/else combination.
If the object on the other hand comes from code you have no way of extending and terse but still clear is what you're going for, you could create a simple helper method;
private bool CallIfType<T>(object obj, Action<T> action) where T : class
{
var concrete = obj as T;
if (concrete == null)
return false;
action(concrete);
return true;
}
You can then write the calls as a simple expression;
var tmp = CallIfType<SpecificClass1>(obj, x => x.SomeMethod1()) ||
CallIfType<SpecificClass2>(obj, x => x.SomeMethod2()) ||
CallIfType<SpecificClass3>(obj, x => x.SomeMethod3());
if(tmp)
Console.WriteLine("One of the methods was called");
Ok, bit rough, but:
public class BaseClass{}
public class SubClass1 : BaseClass
{
public void SomeMethod1()
{
}
}
public class SubClass2 : BaseClass
{
public void SomeMethod2()
{
}
}
public class Class1
{
public Class1()
{
var test = new SubClass1();
var lookup = new Dictionary<Type, Action<object>>
{
{typeof (SubClass1), o => ((SubClass1) o).SomeMethod1() },
{typeof (SubClass2), o => ((SubClass2) o).SomeMethod2() }
};
//probably best to check the type exists in the dictionary first,
//maybe wrap up the execution into a class of it's own so it's abstracted away
lookup[test.GetType()](test);
}
}
How about writing a method
public static class ObjectExtensions
{
public static bool TryCast<T>(this object from, out T to) where T : class
{
to = from as T;
return to != null;
}
}
and using it:
SpecificClass1 sc1;
SpecificClass2 sc2;
SpecificClass3 sc3;
if( obj.TryCast(out sc1) )
{
sc1.SomeMethod1();
}
else if( obj.TryCast(out sc2) )
{
sc2.SomeMethod2();
}
else if( obj.TryCast(out sc3) )
{
sc3.SomeMethod3();
}
Not sure if I'm missing a goal, but here's an option that should work.
if( obj is SpecificClass1 sc1 )
{
sc1.SomeMethod1();
}
else if( obj is SpecificClass2 sc2 )
{
sc2.SomeMethod2();
}
else if( obj is SpecificClass3 sc3 )
{
sc3.SomeMethod3();
}
else
{
throw new exception();
}
You can also
switch (obj)
{
case SpecificClass1 sc1:
sc1.SomeMethod1();
break;
case SpecificClass2 sc1:
sc2.SomeMethod2();
break;
case SpecificClass3 sc1:
sc3.SomeMethod3();
break;
default:
throw new Exception();
}
I have hierarchy of classes:
class A{}
class B: A {}
class C:B {}
is it possible to implement method in class A and it would be inherited by derived classes B and C and so on and that method should return value of class type?
A val = A.method(); (val is A)
B val = B.method(); (val is B)
C val = C.method(); (val is C)
And I don't want use of generics in call of this method, ie:
C val = C.method<C>();
Guys, excuse me, one elaboration, this method should be static.
I don't want to use generic in method istelf, because it forces to point type that method should return, whereas method should return type of its class.
class A
{
Method<T>()
{
T result;
return result;
}
}
If I have such method I can change return type:
D result = A.Method<D>();
but I wanted it to return value of type A;
No, that is not possible.
To call the method like that it would have to be static, and static methods are not inherited.
Using B.method() to call a static method in A is the same as using A.method(). The compiler just uses the type to determine where the method is, but it's impossible for the method to know if it was called using the A or B type.
Use an extension method:
class Program
{
static void Main(string[] args)
{
B x = new B();
x.Method();
}
}
public static class Ext
{
public static T Method<T>(this T obj)
where T : A,new()
{
return new T();
}
}
public class A
{
}
public class B : A
{
}
Or a variation thereof. Note that you must have some public member capable of creating an instance of the specified type. To expound, the compiler 'guesses' the value of the type parameter. The method is still generic, but generic syntax is nowhere to be seen when the method is called (usually).
Using some design patterns from C++ makes this easier:
class A
{
protected virtual A method_impl() { return new A(); }
public A method() { return method_impl(); }
}
class B : A
{
protected override A method_impl() { return new B(); }
public new B method() { return (B)method_impl(); }
}
class C : B
{
protected override A method_impl() { return new C(); }
public new C method() { return (C)method_impl(); }
}
Of course, this exact problem never arises in C++, which allows covariant return types for overrides.
Another way, using IoC pattern:
class A
{
protected virtual void method_impl(A a) { a.initialize(); }
public A method() { A result = new A(); method_impl(result); return result; }
}
class B : A
{
public new B method() { B result = new B(); method_impl(result); return result; }
}
class C : B
{
public new C method() { C result = new C(); method_impl(result); return result; }
}
I have the following generic classes:
class Base<T> where T : ... { ... }
class Derived<T> : Base<T> where T : ... { ... }
class Another<T> where T : ... { ... }
class DerivedFromDerived<T> : Derived<T> where T : ... { ... }
Somewhere in my code, I would like to test whether a given generic inherits from Base<T>, without creating a particular instance of the generic. How do I do that?
static bool DerivedFromBase(Type type) { /* ??? */ }
static void Main(string[] args)
{
Console.WriteLine(DerivedFromBase(typeof(Derived<>))); // true
Console.WriteLine(DerivedFromBase(typeof(Another<>))); // false
Console.WriteLine(DerivedFromBase(typeof(DerivedFromDerived<>))); // true
Console.ReadKey(true);
}
EDIT: Thank you Mark. Now I see the light. I originally tried the following:
typeof(Derived<>).BaseType == typeof(Base<>)
Apparently, this is correct. But it is not. The problem is that Base's T is not the same thing as Derived's T. So, in
typeof(Base<>)
Base's T is a free type. But, in
typeof(Derived<>).BaseType
Base's T is bound to Derived's T, which is in turn a free type. (This is so awesome I would LOVE to see the System.Reflection's source code!) Now,
typeof(Derived<>).BaseType.GetGenericTypeDefinition()
unbounds Base's T. Conclusion:
typeof(Derived<>).BaseType.GetGenericTypeDefinition() == typeof(Base<>)
And now, if you all excuse me, my head is burning.
Not sure if this is what you are looking for but I think "IsAssignableFrom" will do the trick.
class Program
{
class Base<T> { }
class Derived<T> : Base<T> { }
class Another<T> { }
class DerivedFromDerived<T> : Derived<T> { }
static bool DerivedFromBase<T>(Type type)
{
return typeof(Base<T>).IsAssignableFrom(type);
}
static void Main(string[] args)
{
Console.WriteLine(DerivedFromBase<int>(typeof(Derived<int>))); // true
Console.WriteLine(DerivedFromBase<int>(typeof(Another<int>))); // false
Console.WriteLine(DerivedFromBase<int>(typeof(DerivedFromDerived<int>))); // true
Console.ReadKey(true);
}
}
To handle the open base type:
static bool DerivedFromBase(Type type)
{
Type openBase = typeof(Base<>);
var baseType = type;
while (baseType != typeof(Object) && baseType != null)
{
if (baseType.GetGenericTypeDefinition() == openBase) return true;
baseType = baseType.BaseType;
}
return false;
}
I've come up with this version, although it seems a little hacky.
private static bool IsDerivedFrom(Type derivedType, Type baseType)
{
if (derivedType.BaseType == null)
return false;
if (derivedType.BaseType.GUID == baseType.GUID)
return true;
return IsDerivedFrom(derivedType.BaseType, baseType);
}
It relies on all types having different GUIDs, which should be true, but obviously a collision will happen next Thursday.