Similar questions I have found, but I am still having troubles:
Dynamically create an object of <Type>
Get a new object instance from a Type
-- A better description of the problem, hopefully?----
When I call the web service, the response that is brought back is an xml document. That document defines the class that is being returned and then all the values are set through deserializing the xml into 1 of the 8 different types.
Now when I do receipt.Item I get the type that is returned; but because of the way the interface is set up with the web service call I can't access any of the items member variables unless I type cast receipt.Item. That is being done with the switch case. But I want the create the object outside of the switch case and initialize it inside the switch case so I can access it later in the code. That is why I do not create a new object of that type in the switch case and do my work there (or call a function).
I have an overarching return type of Response from a web service that I am calling and the web service can have 8 different result types. I need to create a instance of the 1 of the 8 return types that can be returned.
So here is the structure for a more visual purpose
Response
accountUpdaterRespType
endOfDayRespType
flexCacheRespType
The code for the response objects:
public partial class Response {
private object itemField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute("AccountUpdaterResp", typeof(accountUpdaterRespType))]
[System.Xml.Serialization.XmlElementAttribute("EndOfDayResp", typeof(endOfDayRespType))]
[System.Xml.Serialization.XmlElementAttribute("FlexCacheResp", typeof(flexCacheRespType))]
public object Item {
get {
return this.itemField;
}
set {
this.itemField = value;
}
}
}
When I get the return object of Response I can get the type by doing responseObject.Item and do a GetType() on that. So that is what I have available to me to attempt to type cast a new object.
I have to do this because when I do responseObject.Item I don't have access to the different variables that are in the different object types. So I am trying to type cast a new object in a switch case like so:
object newReceipt = Receipt.GetType(); //this is where I would get the type I assume?? I don't know
string type = Receipt.Item.GetType().ToString();
switch (type)
{
case "accountUpdaterRespType":
newReceipt = (accountUpdaterRespType)Receipt.Item;
break;
case "endOfDayRespType":
newReceipt = (endOfDayRespType)Receipt.Item;
break;
case "flexCacheRespType":
newReceipt = (flexCacheRespType)Receipt.Item;
break;
}
I'll try to restate your question before answering it.
You're trying to create a typed reference to existing instance. You already have an instance of an object, held in a variable of type object, but want to cast it up in order to be able to access members.
By getting variable type in code, you still won't be able to access object members in development time.
Using strings to check object type is not a good idea. Working solution to your problem would be following
// as is a type of cast. if Receipt is of type cast,
// it will return an object and put it into accountUpdater
// variable. If Receipt is not of that type, it will place null
// into accountUpdater variable
var accountUpdater = Receipt.Item as accountUpdater;
if (accountUpdater != null)
{
// Do something with account updater here. E.g.
Console.WriteLine(accountUpdater.SomeAccountUpdaterProperty);
}
var endOfDayResp = Receipt.Item as endOfDayRespType;
if (endOfDayResp != null)
{
// Do something with endOfDayResp here
}
var flexCache = Receipt.Item as flexCacheRespType;
if (flexCache != null)
{
// Do something with flex cache here
}
You get the idea. Mind you, this is not a very nice way to write code. Example above is just to get you up and running. You should get acquainted with object-oriented programming concepts, and for this case particularly, polymorphism.
Another (essentially same) way to handle this would be:
var accountUpdater = Receipt.Item as accountUpdater;
if (Receipt.Item is accountUpdater)
HandleAccountUpdater((accountUpdater)Receipt.Item);
else if (Receipt.Item is endOfDayRespType)
HandleEndOfDay((endOfDayRespType)Receipt.Item);
else if (Receipt.Item is flexCacheRespType)
HandleFlexCache((flexCacheRespType)Receipt.Item);
else
throw new InvalidArgumentException("Unexpected parameter type");
You are correct, polymorphism is a solution in situations where objects have similar traits and need to be handled in similar fashion. Two solutions above are best way you can do without learning a little bit more about C# language. Second solution provides better separation of responsibilities.
You can get more generic solution using reflection. Using methods in System.Reflection you can make a more generic resolution of handler methods. Take following for example:
You have Response object such as you described. You also have a class which can handle different types of objects. For example:
public class ResponseHandler
{
public void Handle(accountUpdater parameter) { /* */ }
public void Handle(endOfDayRespType parameter) { /* */ }
public void Handle(flexCacheRespType parameter) { /* */ }
public void Handle(TypeD parameter) { /* */ }
public void Handle(TypeE parameter) { /* */ }
...
}
Once you receive response, you will be able to determine which handler to call dynamically, without adding each and every type manually, like so:
var handler = new ResponseHandler();
var handlerClassType = typeof(ResponseHandler); // This is how you get Type object from a type. Unlike, `GetType` on objects
var paramType = Response.Item.GetType();
// Get me method which is named Handle and takes parameters in parameter array
// handlerMethod will be of type MethodInfo. This is basically a descriptor of a
// method. Not a pointer to a method or some such...
var handlerMethod = handlerClassType.GetMethod("Handle", new Type[] { paramType });
// Throw exception if we don't know how to handle it
if (handlerMethod == null)
throw new Exception("Handler not found for received response type");
// Invoke the handler. We need to provide the method descriptor with object which
// should execute the method, and parameters that the method takes
handlerMethod.Invoke(handler, new object[] { Response.Item });
This is written here in SO editor, so it may not run right away :)
To expand on Nikola Radosavljević's first answer, you could create an extension method like this:
public static IfType<T>(this object o, Action<T> action) {
var asType = o as T;
if (asType != null) {action(asType);}
}
Then you could do the following, giving you design-time access to all the members of each specific type:
Receipt.Item.IfType<accountUpdater>(r => {
Console.WriteLine(r.SomeAccountUpdaterProperty);
});
Receipt.Item.IfType<endOfDayResp>(r => {
//Do something with endOfDayResp here
});
Receipt.Item.IfType<flexCacheResp>(r => {
//Do something with flexCacheResp here
});
Still a lot of noise, but a bit more concise.
To do this the OOP way, define an interface:
interface IResponseItem {
void DoAction();
}
Then, each item type should implement the IResponseItem interface:
public class AccountUpdater : IResponseItem {
private int data;
public void DoAction() {
Console.WriteLine(data);
}
}
Then, you define the type of Response.Item as IResponseItem, and you can call the DoAction directly, without knowing the actual (a.k.a. concrete) type of the item:
Response.Item.DoAction();
This is polymorphism - having a common base type (IResponseItem) with multiple inheriting/implementing types (AccountUpdater etc.) that implement the same member (DoAction) to do different things. (Polymorphism in the C# Programming Guide on MSDN)
Your problem could be solved with the implementation of either an interface or an abstract base class.
If a type implements other types, you can store in a lower typed variable. For instance, in .Net every type is derived from the basic class object. This is allows you to store a List, a String and every other type in a object variable.
Similar, you can use interfaces to store instances that implement that interface. A interface is basically a list of methods and properties that a class needs to implement.
In your case I'd suggest you should add a higher level of abstraction. For instance you could create a interface
interface IResponse {
int StatusCode {get;}
string Content {get;}
...
}
You could implement this interface in every response.
public class EndOfDayResponse : IResponse
{ ... }
The type of Receipt.Item would then be IResponse instead of object. You could then check the actual type with response is EndOfDayResponse and then do the appropriate casting.
Related
I have a list of objects ListOfObjects that are all of the same type, but the specific type is not known (however, I do know all the possible types). There are
many possible types. Each object has the property Name, which is a string of its type. I want do something like the following:
foreach (object elements in ListOfObjects)
{
// Some code here that casts elements into the specific type and pass it into another function
}
I know one way to do this is to use a switch case statement
switch (ListOfObjects[0].Name)
{
case "Type1":
//cast into Type1 and pass into function
case "Type2":
//cast into Type2 and pass into function
default:
//something
break;
}
Is there a cleaner way to do this? Is is possible to store the possible Types in a dictionary and cast from that dictionary?
Pattern Matching
To start I want to present the use of pattern matching in switch statements to work with different types, as follows:
public static double ComputeAreaModernSwitch(object shape)
{
switch (shape)
{
case Square s:
return s.Side * s.Side;
case Circle c:
return c.Radius * c.Radius * Math.PI;
case Rectangle r:
return r.Height * r.Length;
default:
throw new ArgumentException(
message: "shape is not a recognized shape",
paramName: nameof(shape));
}
}
Example taken from Pattern Matching - C# Guide.
Type Dictionary
With that out of the way, yes, you can write a dictionary... the trouble will be on the type of the items.
We can do this:
Dictionary<Type, Action<object>> dictionary;
// (initialize and populate somewhere else) ...
if (dictionary.TryGetValue(element.GetType(), out var action))
{
action(element);
}
However, here you have to use Action<object> because we need to give a type to the items (and no, we can't say Action<?> - well, we can do Action<dynamic> but you cannot cast Action<someType> to Action<dynamic>), forcing you to cast inside the called method.
We can argue that a cast is a way to tell the compiler that we know something it does not. In this case that we know that that object is actually of a given type.
We could do a bit better/worse, depending on how you look at it...
Dictionary<Type, Delegate> dictionary;
// (initialize and populate somewhere else) ...
if (dictionary.TryGetValue(element.GetType(), out var #delegate))
{
#delegate.DynamicInvoke(element);
}
This is effectively late binding. We do not know the types at compile time... as developer you must ensure you provide a delegate of the correct type. However, if we are already enforcing knowledge that the compiler is unaware of, then this could be acceptable.
We can make a helper method to make it easier:
void SetMethod<T>(Action<T> action)
{
dictionary[typeof(T)] = action;
}
Here the compiler can check the type for the method is correct. Yet, from the point of view of the compiler this information is lost (not available) when you consume the dictionary. It is a kind of type erasure if you will.
Dynamic
Now, if we are forgoing types, we could use dynamic following good answer by TheGeneral.
Addendum: Calling a known method (with MethodInfo)
You can call a method by its name, for example, if you have the following:
class Helper
{
public static void Method(T input)
{
Console.WriteLine(input.GetType());
}
}
You can do this:
var methodInfo = typeof(Helper).GetMethod("Method");
// ...
methodInfo.Invoke(null, new object[]{element});
You could then put all your methods in a helper class, and find them by the name (which you could derive from the name of the type).
If you want to call a known method that has a generic parameter, you can use MethodInfo. We need to be aware of whatever or not the method is static, and whatever or not the generic argument is part of the method definition or the declaring type definition...
On one hand, if you have something like this:
class Helper<T>
{
public static void Method(T input)
{
Console.WriteLine(input.GetType());
}
}
You can do this:
var helperType = typeof(Helper<>);
// ...
var specificMethodInfo = helperType.MakeGenericType(element.GetType()).GetMethod("Method");
specificMethodInfo.Invoke(null, new object[]{element});
On the other hand, if you have this:
class Helper
{
public static void Method<T>(T input)
{
Console.WriteLine(input.GetType());
}
}
You can do this:
var methodInfo = typeof(Helper).GetMethod("Method");
// ...
var specificMethodInfo = methodInfo.MakeGenericMethod(element.GetType());
specificMethodInfo.Invoke(null, new object[]{element});
Note: I pass null as first parameter to invoke. That is the instance on which I am calling the method. None, because they are static. If they aren't then you need an instance... you could try creating one with Activator.CreateInstance, for example.
Addendum: Finding what to call (Type Discovery)
Perhaps you have disparate method to call (they are not the same but with different generic argument), but you do not want to have the trouble of populate the dictionary by hand.
That is where Type Discovery comes in.
To begin with, I suggest to use an attribute, for example:
[AttributeUsage(AttributeTargets.Method)]
public sealed class DataHandlerAttribute : Attribute { }
Then we need a list of the types where we will search. If we will search on a known assembly we could do this:
var assembly = typeof(KnownType).GetTypeInfo().Assembly;
var types = assembly.GetTypes();
Note: if your target platform does not support this (.NET Standard 1.0 to 1.4), you will have to hand code the list of types.
Next, we need a predicate to check if a given type is one of the ones in which we are interested:
bool IsDataHandlerMethod(MethodInfo methodInfo)
{
var dataHandlerAttributes = return (DataHandlerAttribute[])item.GetCustomAttributes(typeof(DataHandlerAttribute), true);
if (attributes == null || attributes.Length == 0)
{
return false;
}
if (methodInfo.DeclaringType != null)
{
return false;
}
if (methodInfo.ReturnTpye != typeof(void))
{
return false;
}
var parameters = methodInfo.GetParameters();
if (parameters.Length != 1)
{
return false;
}
if (paramters[0].IsByRef || paramters[0].IsOut)
{
return false;
}
return true;
}
And a method to convert them into delegates:
(Type, Delegate) GetTypeDelegatePair(MethodInfo methodInfo)
{
var parameters = methodInfo.GetParameters();
var parameterType = parameters[0].ParameterType;
var parameterTypeArray = new []{parameterType};
var delegateType = typeof(Action<>).MakeGenericType(parameterTypeArray);
var target = null;
if (!methodInfo.IsStatic)
{
var declaringType = methodInfo.DeclaringType;
target = instance = Activator.CreateInstance(declaringType);
}
return (parameterType, methodInfo.CreateDelegate(delegateType, target));
}
And now we can do this:
var dataHandlers = types
.SelectMany(t => t.GetTypeInfo().GetMethods())
.Where(IsDataHandlerMethod)
.Select(GetTypeDelegatePair);
And we will have an enumerable of pairs of types and delegate that we can use to populate our dictionary.
Note: the above code still needs some work (for example, could we just call GetParameters once?), and presumes a modern .NET target (extra work is needed to make it work in older platforms). Also notice the code for Type Discovery I present does not handle generic methods, you can check Type.IsGenericTypeDefinition and MethodInfo.IsGenericMethodDefinition... however, I would suggest to avoid them. In fact, it should be easy to modify for the case where you want to put all the methods in a single static class. You may also use a similar approach to get factory methods, for example.
If you have overloads, and you don't want to use a switch, you could use dynamic, however you really need to ask yourself if this is a design problem, and should be solved in a more appropriate way. I.e why do you need to store unrelated types in a list anyway?
public static void Test(Version version)
{
Console.WriteLine("is a version");
}
public static void Test(FormatException formatException)
{
Console.WriteLine("is a formatException");
}
static void Main(string[] args)
{
var list = new List<object>();
list.Add(new Version());
list.Add(new FormatException());
foreach (var item in list)
Test((dynamic)item);
}
Output
is a version
is a formatException
Full Demo Here
Note : this will all break if it can't find an overload. ka-bang! So I don't recommend using it, unless you really need to.
You can actually use standard System properties and methods to achieve your goal.
The first thing to do is get the Type:
var type = System.Type.GetType(elements.Name, false, true);
The false parameter indicates that you do not want to throw an exception on error and the true parameter indicates that you want to ignore case.
Once you have a valid type, you can call System.Activator to create a new instance of the class:
if (type != null) {
var classInstance = System.ServiceActivator.CreateInstance(type);
// Use the instance here
}
Note that this overload of CreateInstance requires a parameterless, public constructor. However, there are other overloads that allow you to pass parameters and access non-public constructors.
You can use Type.GetType method to get the type of object instead of doing a string comparision. Here's the same code:
foreach (var element in ListOfObjects)
{
var type = Type.GetType(element.Name);
if (type == typeof(YOUR_OBJECT_TYPE))
{
// Do Something
}
}
Read more about GetType here
I am not sure if i understand your question clearly but,
maybe it can help you, I don't think you need to keep type in name field since you can get type just like this. And i also don't get why do you want to cast this type again to itself.
foreach (var element in ListOfObjects)
{
var _type = element.getType()
}
and you can just use switch case or if statements for making route.
Surely using dictionary mapping Type and Method is possible:
Dictionary<Type, Action<Object>> methodMap = new Dictionary<Type, Action<Object>>();
Preloading the dictionary:
static void Action1(Object obj)
{
//do necessary casting here or not
Console.WriteLine("i handle Type1");
}
static void Action2(Object obj)
{
Console.WriteLine("i handle Type2");
}
Dictionary<Type, Action<Object>> methodMap = new Dictionary<Type, Action<Object>>();
methodMap[typeof(Type1)] = Action1;
methodMap[typeof(Type2)] = Action2;
And use the dictionary:
List<Object> collector = new List<Object>();
collector.Add(new Type1());
collector.Add(new Type2());
methodMap[collector[0].GetType()](collector[0]);
methodMap[collector[1].GetType()](collector[1]);
The type-method map also works for those class who's ancient is different. it would be the key factor you choose this kind method rather overloading or virtual member function.
I have the situation, where I want to call some generic method on another object and get IEnumerable result.
private void SomeFunction(Type type)
{
var method = context.GetType()
.GetMethods()
.FirstOrDefault(_ => _.Name == "GetStorage" && _.IsGenericMethod);
var storage = getStorage.MakeGenericMethod(type)
.Invoke(context, new object[] {})
.AsEnumerable();
//Some magic needed here. Something like Cast<type>,
//but type - variable
//More code ...
}
Could anyone suggest me how to figure out this situation. Thank you.
I have already seen this and similar questions:
Casting Results from Generic Method Invocation?
But they doesn't answer on my question, how to do same, when I don't know type, to which I want to cast, and type is stored as variable.
I can't makeSomeFunction a generic method, because the real situation is that I am iterating some list with System.Type and calling lambda (i. e. SomeFunction) on each element
There are some things you need to do to get what you want. You say you want to have a lambda, but that means that you need to define that lambda, which is on a type you do not know yet. You can redesign your lambda into an interface.
Also, I find it much easier to define a generic class that does exactly what I want. By creating an instance of this class through reflection, and only there, I can implement the rest of the class in a strong typed way. This takes away the 'not knowing what type I have' in most places.
Like this. First, the executor interface:
public interface ISomeFunctionExecutor
{
void Execute(SomeContext context);
}
Then the interface that I need to implement on the entities, which is the lambda so to speak.
public interface IEntityWithSomeFunction
{
void SomeFunction();
}
Now the implementation of the executor.
public class SomeFunctionExecutor<TType> : ISomeFunctionExecutor
{
public void Execute(SomeContext context)
{
var data = context.GetStorage<TType>().Cast<IEntityWithSomeFunction>();
foreach (var item in data)
{
item.SomeFunction();
}
}
}
And finally, the usage of it all:
// Usage:
SomeContext context = new SomeContext();
Type type = typeof(SomeEntity);
var executorType = typeof(SomeFunctionExecutor<>).MakeGenericType(type);
var executor = Activator.CreateInstance(executorType) as ISomeFunctionExecutor;
if (executor != null)
{
executor.Execute(context);
}
Basically the point is: define a generic class to do what you need to do where you do know the type, and create an instance of this class using reflection. It makes it much easier than having a whole method where you do not know the type.
I'm trying to create an instance of specified Type whatever user wants to have. For a quick illustration of my purpose please see the code below:
static void Main(string[] args)
{
object o = GetInstance(typeof(int));
Console.WriteLine("Created type: {0}", o.GetType().FullName);
}
public static object GetInstance(Type t)
{
Console.WriteLine("Creating instance of {0}", t.FullName);
return Activator.CreateInstance(t);
}
The problem is Activator.CreateInstance() returns object by default. There is also an overload of this method like T Activator.CreateInstance<T>() which is parameterless and returns the type you specify as T.
However, the problem is T should be hard-coded while calling this method and thus should be a fixed value. I am trying to create an instance of desired class and return it as its type.
Right now if you use this method you should write something like:
int i = GetInstance(typeof(int)) as int
I'm trying to reduce this to:
int i = GetInstance(typeof(int))
Is there a way that I can do casting inside the GetInstance and get rid of that as int repetition? By this way, my return type (and also the type I cast the object to) will be unknown at compile time.
Seemed impossible by design to me but I'd really appreciate if you figure it out.
EDIT: Where I'm stuck is e.g. while you're casting, you can do return (T) result if you are in a generic method, but you can't do Type t = ...; return (t) result this doesn't work. You cannot cast to a type which is passed to you as a parameter which is not known at compile time.
Follow a known pattern
This is not a new problem. It is a problem facing any API that allows type-specific return values. For example, a JSON parsing library like Newtonsoft (which is, to wit, the single most popular .NET package downloaded by .NET programmers in 2019) must be able to parse a string and return a type-specific object, which may or may not be known at compile time. It might make sense to follow their example.
Newtonsoft exposes three ways to specify the type when deserializing. You could do as you are currently doing:
//Cast required
var result = JsonConvert.DeserializeObject(text, typeof(MyType)) as MyType;
You can use a generic method:
//No cast required, but you have to hardcode a type as a type parameter
var result = JsonConvert.DeserializeObject<MyType>(text);
Or you can use an instance as a template, which is great for anonymous types, although you can use it with non-anonymous classes as well. This one works via generic type inference:
//No cast required and no need to specify type; the type is inferred from the argument
var result = JsonConvert.DeserializeAnonymousType(text, new MyType());
Here's how you'd do it:
So for you to make this work, your code might look like this:
public object GetInstance(Type type)
{
return Activator.CreateInstance(type);
}
int i = GetInstance(typeof(int)) as int;
public T GetInstance<T>()
{
return Activator.CreateInstance<T>();
}
int i = GetInstance<int>();
public T GetInstance<T>(T template)
{
return Activator.CreateInstance<T>();
}
int i = GetInstance(0);
If you do it this way, it's hard to imagine any programmer would have trouble using your library, as the approach should already be familiar to them.
Actually you could write GetInstance like this:
static T GetInstance<T>()
{
return Activator.CreateInstance<T>();
}
And use it:
int j = GetInstance<int>();
This might help you to create instance of desired type:
public class ConcreteFactory<T> : AbstractFactory<T>
{
public override T CreateInstance(string typeName,params object[] parameters)
{
var path = Assembly.GetExecutingAssembly().CodeBase;
var assembly = Assembly.LoadFrom(path);
var type = assembly.GetTypes().SingleOrDefault(t => t.Name == typeName);
return (T)Activator.CreateInstance(type, parameters);
}
}
Key here is generic type T can be used to cast the created instance, this can be used as a template to create instance of any type with parameterized constructor
I am having a problem with the return type of a method.
The method returns a linq object which at present returns type tblAppointment. This method is shown below:
public tblAppointment GetAppointment(int id)
{
var singleAppointment = (from a in dc.tblAppointments
where a.appID == id
select a).SingleOrDefault();
return singleAppointment;
}
The problem is that tblAppointment is abstract and has many sub types that inherit it. When I try and return an object that is of Type "appointmentTypeA" and call the .GetType() method on it, it gives me the correct sub type, but when i try and access the properties it only allows me to access the parent properties. If i take the object and cast it to a new object of the subtype then it works and lets me access everything i need but it seems messy.
var viewSingleAppointment = appointmentRepos.GetAppointment(appointmentId);
Debug.Write(viewSingleAppointment.GetType()); //returns type i want
if (viewSingleAppointment is tblSingleBirthAppointment)
{
tblSingleBirthAppointment myApp = (tblSingleBirthAppointment)viewSingleAppointment; //need to do this to access TypeA properties for some reason
}
Edit: I have got this working but I need to use a select statement for each appointment (about 20) and cast them to the appropriate type and retreive the properties and im not sure how to refactor this as it will be used on a few pages we are doing.
You're solving the wrong problem. If you have a superclass A, with subclasses B, C, etc., that all have similar functionality, you want to do the following:
Make A an interface that B, C, etc. implement. Code that works with B or C instances does by working through the interface provided by A. If you can define a common set of operations that work on all the types, then this is all you need to do.
If you can't define a common set of operations, e.g. you have code similar to:
A foo = GetA();
if(foo is B) {
B bFoo = (B) foo;
// Do something with foo as a B
} else if(foo is C) {
C cFoo = (C) foo;
// Do something with foo as a C
} ...
Or even this (which is basically the same thing, just using extra information to emulate what the type system already provides for you):
A foo = GetA();
MyEnum enumeratedValue = foo.GetEnumeratedValue();
switch(enumeratedValue) {
case MyEnum.B:
B bFoo = (B) foo;
// Do something with foo as a B
break;
case MyEnum.C:
C cFoo = (C) foo;
// Do something with foo as a C
break;
}
Then what you really want is to do something like:
A foo = GetA();
foo.DoSomething();
Where each subclass would implement the corresponding branch of the switch statement. This is actually better in several ways:
It uses less overall code.
Since the implementations of the cases live in the various implementation classes, no casting is necessary; they can access all the member variables directly.
Since you're not building a big switch/case block separate from the actual B and C implementations, you don't run any risk of accidentally forgetting to add a corresponding case if add a new subclass. If you leave the DoSomething() method out of a subclass of A, you will get a compile-time error.
Edit: In response to your comment:
If your DoSomething() routine needs to operate on a Form or other GUI element, just pass that element into the method. For example:
public class B : A {
public void DoSomething(MyForm form) {
form.MyLabel.Text = "I'm a B object!";
}
}
public class C : A {
public void DoSomething(MyForm form) {
form.MyLabel.Text = "I'm a C object!";
}
}
// elsewhere, in a method of MyForm:
A foo = GetA();
foo.DoSomething(this);
Alternatively, an even better idea might be to turn your B and C classes into custom controls, since they seem to encapsulate display logic.
Well, if you're using C# 4 you could use dynamic typing... but if you want to stick to static typing, I suspect the best you can do is provide the expected type as a generic type argument, and get the method to perform the cast for you:
public T GetAppointment<T>(int id) where T : tblAppointment
{
var singleAppointment = (from a in dc.tblAppointments
where a.appID == id
select a).SingleOrDefault();
return (T) singleAppointment;
}
Call this with:
SpecificAppointment app = GetAppointment<SpecificAppointment>(10);
or use implicit typing:
var app = GetAppointment<SpecificAppointment>(10);
It will throw an exception at execution time if the cast fails.
This assumes the caller knows the appointment type (although they could specify tblAppointment if they don't). Without knowing the appropriate appointment type at compile-time it's hard to see how static typing can do you any more favours, really...
You could create a generic method :
public T GetAppointment<T>(int id) where T : tblAppointment
{
var singleAppointment = dc.tblAppointments.SingleOrDefault(a => a.appID == id);
return (T)singleAppointment;
}
But then you would need to know the object's actual type before calling it...
When you call .GetType(), you get the runtime type of the object. C# compiler doesn't know what runtime type your object will have. It only knows that your object is going to be of a type derived from tblAppointment because you said so in your method declaration, so the static type of the return value is tblAppointment. Therefore tblAppointment is all you can access, unless you use a cast to tell the compiler «I know that at runtime this reference is going to refer to an object of this type, insert a runtime check and give me a reference with this static type».
Static typing is all about the difference between types as known at compile time and as they are at runtime. If you come from a dynamically typed language like Smalltalk or Javascript, you'll have to make quite a few adjustments to your programming habits and thought processes. E.g., if you have to do something to an object that depends on its runtime type, the solution often is to use virtual functions — they dispatch on the object's runtime type.
Update: in your particular case, use virtual functions, this is exactly what they were made for:
class tblAppointment
{
protected abstract void ProcessAppointment () ;
}
sealed class tblBirthAppointment
{
protected override void ProcessAppointment ()
{
// `this` is guaranteed to be tblBirthAppointment
// do whatever you need
}
}
...
Then use
// will dispatch on runtime type
appointmentsRepo.GetAppointment (id).ProcessAppointment () ;
You could create another method to encapsulate the cast:
public tblSingleBirthAppointment GetBirthAppointment(int id)
{
var singleAppointment = GetAppointment(id);
if (singleAppointment != null)
{
return (tblSingleBirthAppointment)singleAppointment;
}
return null;
}
That method would break if you tried to use it with an ID that wasn't actually a BirthAppointment though, so you might consider checking.
var viewSingleBirthAppointment = appointmentRepos.GetBirthAppointment(appointmentId);
If you are returning reference to a child type that is a parent type, the reference will be of that type and the compiler will not allow you to access any of the child type's members until you cast to that type. This is polymorphism in action :)
The good news is that you are not creating a new object when you cast a reference type - you are simply changing the type of the reference that points to the object you already have thereby giving you access to its members.
The topic of how C# virtual and override mechanism works internally has been discussed to death amongst the programmers... but after half an hour on google, I cannot find an answer to the following question (see below):
Using a simple code:
public class BaseClass
{
public virtual SayNo() { return "NO!!!"; }
}
public class SecondClass: BaseClass
{
public override SayNo() { return "No."; }
}
public class ThirdClass: SecondClass
{
public override SayNo() { return "No..."; }
}
class Program
{
static void Main()
{
ThirdClass thirdclass = new ThirdClass();
string a = thirdclass.SayNo(); // this would return "No..."
// Question:
// Is there a way, not using the "new" keyword and/or the "hide"
// mechansim (i.e. not modifying the 3 classes above), can we somehow return
// a string from the SecondClass or even the BaseClass only using the
// variable "third"?
// I know the lines below won't get me to "NO!!!"
BaseClass bc = (BaseClass)thirdclass;
string b = bc.SayNo(); // this gives me "No..." but how to I get to "NO!!!"?
}
}
I think I can't get to the methods of base class or the intermediate derived class simply using the most derived instance (without modifying the method signatures of the 3 classes). But I would like to confirm and cement my understanding...
Thanks.
C# can't do this but it is actually possible in IL using call instead of callvirt. You can thus work around C#'s limitation by using Reflection.Emit in combination with a DynamicMethod.
Here's a very simple example to illustrate how this works. If you really intend to use this, wrap it inside a nice function strive to make it work with different delegate types.
delegate string SayNoDelegate(BaseClass instance);
static void Main() {
BaseClass target = new SecondClass();
var method_args = new Type[] { typeof(BaseClass) };
var pull = new DynamicMethod("pull", typeof(string), method_args);
var method = typeof(BaseClass).GetMethod("SayNo", new Type[] {});
var ilgen = pull.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.EmitCall(OpCodes.Call, method, null);
ilgen.Emit(OpCodes.Ret);
var call = (SayNoDelegate)pull.CreateDelegate(typeof(SayNoDelegate));
Console.WriteLine("callvirt, in C#: {0}", target.SayNo());
Console.WriteLine("call, in IL: {0}", call(target));
}
Prints:
callvirt, in C#: No.
call, in IL: NO!!!
Without modification to your sample and discounting reflection, no there is no way. The intent of the virtual system is to enforce calling the derived most no matter what and the CLR is good at its job.
There are a couple of ways you can work around this though.
Option 1: You could add the following method to ThirdClass
public void SayNoBase() {
base.SayNo();
}
This would force the invocation of SecondClass.SayNo
Option 2: The main problem here is that you want to invoke a virtual method non-virtually. C# only provides one way of doing this via the base modifier. This makes it impossible to call a method within your own class in a non-virtual fashion. You can fix this by factoring it out into a second method and proxying.
public overrides void SayNo() {
SayNoHelper();
}
public void SayNoHelper() {
Console.WriteLine("No");
}
Sure...
BaseClass bc = new BaseClass();
string b = bc.SayNo();
"Virtual" means that the implementation which will be executed is based on the ACTUAL type of the underlying object, not the type of the variable it is stuffed in... So if the actual object is a ThirdClass, that's the implementation you will get, no matter what you cast it to. If you want the behavior you describe above, don't make the methods virtual...
If you're wondering "what's the point?" it's for 'polymorphism'; so that you can declare a collection, or a method parameter, as some base type, and include/ pass it a mix of derived types, and yet when, within the code, even though each object is assigned to a ref variable declared as the base type, for each one, the actual implementation which will be executed for any virtual method call will be that implementation defined in the class definition for the ACTUAL tyoe of each object...
Using base in C# only works for the immediate base. You can't access a base-base member.
It looks someone else beat me to the punch with the answer about it being possible to do in IL.
However, I think the way I did the code gen has some advantages, so I'll post it anyways.
The thing I did differently is to use expression trees, which enable you to use the C# compiler to do overload resolution and generic argument substitution.
That stuff is complicated, and you don't want to have to replicate it your self if you can help it.
In your case, the code would work like this:
var del =
CreateNonVirtualCall<Program, BaseClass, Action<ThirdClass>>
(
x=>x.SayNo()
);
You would probably want to store the delegate in a readonly static field, so that you only have to compile it once.
You need to specify 3 generic arguments:
The owner type - This is the class that you would have invoked the code from if you were not using "CreateNonVirtualCall".
The base class - This is the class you want to make the non virtual call from
A delegate type. This should represent the signature of the method being called with an extra parameter for the "this" argument. It's possible to eliminate this, but it requires more work in the code gen method.
The method takes a single argument, a lambda representing the call. It has to be a call, and only a call. If you want to extend the code gen you can support more complex stuff.
For simplicicty, the lambda body is restricted to only being able to access lambda parameters, and can only pass them in directly to the function. You can remove this restriction if you extend the code gen in the method body to support all expression types. That would take some work though. You can do anything you want with the delegate that comes back, so the restriction isn't too big of a deal.
It's important to note that this code is not perfect. It could use a lot more validation, and it doesn't work with "ref" or "out" parameters because of expression tree limitations.
I did test it in sample cases with void methods, methods returning values, and generic methods, and it worked. I'm sure, however, you can find some edge cases that don't work.
In any case, here's the IL Gen Code:
public static TDelegate CreateNonVirtCall<TOwner, TBase, TDelegate>(Expression<TDelegate> call) where TDelegate : class
{
if (! typeof(Delegate).IsAssignableFrom(typeof(TDelegate)))
{
throw new InvalidOperationException("TDelegate must be a delegate type.");
}
var body = call.Body as MethodCallExpression;
if (body.NodeType != ExpressionType.Call || body == null)
{
throw new ArgumentException("Expected a call expression", "call");
}
foreach (var arg in body.Arguments)
{
if (arg.NodeType != ExpressionType.Parameter)
{
//to support non lambda parameter arguments, you need to add support for compiling all expression types.
throw new ArgumentException("Expected a constant or parameter argument", "call");
}
}
if (body.Object != null && body.Object.NodeType != ExpressionType.Parameter)
{
//to support a non constant base, you have to implement support for compiling all expression types.
throw new ArgumentException("Expected a constant base expression", "call");
}
var paramMap = new Dictionary<string, int>();
int index = 0;
foreach (var item in call.Parameters)
{
paramMap.Add(item.Name, index++);
}
Type[] parameterTypes;
parameterTypes = call.Parameters.Select(p => p.Type).ToArray();
var m =
new DynamicMethod
(
"$something_unique",
body.Type,
parameterTypes,
typeof(TOwner)
);
var builder = m.GetILGenerator();
var callTarget = body.Method;
if (body.Object != null)
{
var paramIndex = paramMap[((ParameterExpression)body.Object).Name];
builder.Emit(OpCodes.Ldarg, paramIndex);
}
foreach (var item in body.Arguments)
{
var param = (ParameterExpression)item;
builder.Emit(OpCodes.Ldarg, paramMap[param.Name]);
}
builder.EmitCall(OpCodes.Call, FindBaseMethod(typeof(TBase), callTarget), null);
if (body.Type != typeof(void))
{
builder.Emit(OpCodes.Ret);
}
var obj = (object) m.CreateDelegate(typeof (TDelegate));
return obj as TDelegate;
}
You can't get to the base methods of an override. No matter how you cast the object, the last override in the instance is always used.
If its backed with a field you could pull out the field using reflection.
Even if you pull off the methodinfo using reflection from typeof(BaseClass) you will still end up executing your overridden method