I have a C# wraper class with a series of methods accepting various data types:
public class MyClass
{
public void ProcessString(string Value) { // implementation }
public void ProcessInt(int? Value) { // implementation }\
public void ProcessOther(MyClass Value) { // implementation }
}
I now want to add a generic ProcessObject() method to avoid the need to explicitly cast an object before calling a relevant process method:
public void ProcessObject(object Value)
{
if (CanCastToString(Value)
{
ProcessString((string)Value);
}
else if (CanCastToInt(Value))
{
ProcessInt((int?)Value);
}
// etc...
}
The trouble is that I don't know what my CanCastToInt methods should be - I need these methods to be able to be robust and deal with things like nullable types and other user defined casts.
How can I do this? All I want to know is if a given object can be cast to a given type, i.e. whether or not:
(SomeType)Value
Will work.
There are two main ways this is usually done:
if (Value is SomeType)
{
// Do something with a cast
}
or
var v = Value as SomeType;
if (v != null)
{
// Value was successfully cast as SomeType
}
When working with structs or intrinsic types, make them nullable:
var v = Value as int?;
if (v != null)
{
ProcessInt(v.Value);
}
you need is operator. CanCastToString(x) -> x is string.
Why not expose your processing API directly, with overloads for various parameters?
public class MyClass
{
public void Process(string Value) { // implementation }
public void Process(int Value) { // implementation }\
public void Process(MyClass Value) { // implementation }
public void Process(object Value) { // catch all method. Handle unknown entities, e.g. call ToString() }
}
EDIT With some generics magic you can have a single interface method, a bunch of helper methods that do the work and one catch-all method where you handle corner cases.
public class MyClass
{
void DoProcess(string Value) { // implementation }
void DoProcess(int Value) { // implementation }\
void DoProcess(MyClass Value) { // implementation }
void DoProcess(object Value) {
// catch all method. Handle unknown entities, e.g. call ToString()
}
public void Process<T>(T value) {
//this method will call the right overload of DoProcess depending on the compile time type of value. If there isn't a match, it goes to DoProcess(object)
DoProcess(value);
}
}
This way you avoid boxing for fundamental types and have slightly better type safety.
For your catch-all method you can try using Type.IsAssignableFrom method. For example:
if (typeof(short).IsAssignableFrom(Value)
DoProcess((short)Value);
if (typeof(byte).IsAssignableFrom(Value)
DoProcess((byte)Value);
I do recommend that you read Eric Lippert's essay about representation casts. Hopefully, after doing that, you will come to realisation that it might just be easier to have an overload for each supported type. Also, you might realise that dealing with unboxing value types could be a road to hell.
If (unlike OP?) you don't know the type involved until runtime you may try to employ some variation of this:
http://codegoeshere.blogspot.com/2007/05/dynamic-cast-in-c.html
public void QuickTest()
{
object stringObj = "string";
object nullableInt1 = (int?)null;
object nullableInt2 = (int?)1;
object decimalObj = 1.5m;
ProcessObject(stringObj);
ProcessObject(nullableInt1);
ProcessObject(nullableInt2);
ProcessObject(decimalObj);
}
public void ProcessObject(object value)
{
if (value == null)
{
Debug.WriteLine("null");
return;
}
if (value is string)
{
Debug.WriteLine((string)value);
return;
}
string stringValue = value.ToString();
int intTemp;
if (int.TryParse(stringValue, out intTemp))
{
Debug.WriteLine(intTemp);
return;
}
decimal decimalTemp;
if (decimal.TryParse(stringValue, out decimalTemp))
{
Debug.WriteLine(decimalTemp);
return;
}
// etc...
}
Related
I would like to create a function allow to get data from any classes with provide a key value, but I am stack when converting object back to the class. The following is my code.
var ListABC = new List<ABC>();
GetData(ListABC, typeof(ABC), "A1");
Here is my Function :-
Public void GetData(object obj, Type objType, string find)
{
// Note! not able to using (List<ABC>)obj, because you never know what tyoe of object will be pass in.
// How to get list data of "A1" after List ABC as a object? assume this function allow any classes.
}
Here is my class :-
public class ABC {
protected int _A1;
protected bool _B1;
protected string _C1;
public int A1
{
get
{
return this._A1;
}
set
{
this._A1 = value;
}
}
public bool B1
{
get
{
return this._B1;
}
set
{
this._B1 = value;
}
}
public string C1
{
get
{
return this._C1;
}
set
{
this._C1 = value;
}
}
}
As Daniel said, make GetData generic:
public void GetData<T>(IList<T> obj, string find)
{
}
and then call it like so:
GetData(ListABC, "A1");
You can even enforce constraints on T, for example:
public void GetData<T>(IList<T> obj, string find)
where T: IConvertible
{
}
If you don't want to implement an interface on the list item objects you will pass here, you could also pass a func:
public void GetData<T>(IList<T> obj, Func<T, string> idFunc, string find)
{
var matchingItems = obj.Where(o => idFunc(o) == find);
}
and call it like so:
GetData(ListABC, i => i.A1, "A1");
Edit: Do you just want ListABC.Select(i => i.A1) ?
If you want minimum change in your code. you can do it like below.
Although, making method generic is good idea, but as you are already passing type of ABC to the method, you are not required to make method generic.
here type you have passed is suggesting which type of data list is holding
Assumptions: you method's return type is void (so assuming you don't want anything to be returned. and also you are passing only one string find as a property to get so at a time you want data of only specified property.
if your requirements are simpler and scope of data is limited in your method only, you can always choose simpler way (which is easily understandable and readable)
try something like below,
public void GetData(object obj, Type objType, string find)
{
//as you are passing type of list here, you can use it.
if(objType == typeof(ABC))
{
List<ABC> list = (List<ABC>)obj;
//now use it.
//here we are getting the property with name as per find (name we passed in method)
PropertyInfo prop = objType.GetProperty(find);
//if there is no property with specified name, PropertyInfo object (prop) will be null
if (prop != null)
{
if (prop.PropertyType == typeof(int))
{
foreach (ABC abcObj in list)
{
object a1Data = prop.GetValue(abcObj);
int data = (int)a1Data;
}
}
}
}
}
Note: drawback of this approach is, you need to handle cases of different Types in this method. So if your method may accept big variety of type, you may not want to go with this idea.
A sample code I tried to return an instance of class is given below.
public object getConstructorclass(int i)
{
if(i==1)
{
Type type = Type.GetType("test1");
}else
{
Type type = Type.GetType("test2");
}
return Activator.CreateInstance(type);
}
var objcls = getConstructorclass(1);
objcls.callclass();//error occured
How can I mention the class type here since the type is not known at compile time but it will decided at runtime.In the above example i just pass a value 1 (it can be anything and that class will be called accordingly), and the class test1 called.
here I will get an error on the line objcls.callclass(), because objcls is an object instance that doesn't have a callclass()method.
How can I restructure this piece of code? My aim is if I mention a class in the getConstructorclass() method, an object should be returned so as to use it in the further code to invoke the members of that class.
If you know that your classes will have this method, you should use a common interface for them and implement it accordingly. Then you will work with classes that you have made sure it will work.
It would look like this
IMyInterface objcls = getconstrorclass() as IMyInterface;
if (objcls != null)
objcls.callclass();
else
// we failed miserably and should do something about it
I don't think you should use some generic object returning constructor based on an int variable, if your classes don't have anything in common. It's really weird to handle it like this and it may lead to various problems (some of which you're currently already experiencing). Generic class constructors make sense if the classes are somewhat related and you can predict the outcome, but to create a do-it-all method.. Not so sure about correctness of such approach.
Anyway, if you insist (not recommended, but as you wish), you can create some checks for a type like this:
var createdObject = getConstructorclass(1);
if (createdObject is MyClass1)
{
var specificObject = (MyClass1)createdObject;
specificObject.callMethod1();
}
else if (createdObject is MyClass2)
{
var specificObject = (MyClass2)createdObject;
specificObject.callSomeOtherMethod();
}
...
But it gets very error prone soon, refactoring will probably be a nightmare etc., but it's your call..
Or you maybe can use solution from pwas, but to me it seems unnecessarily complicated for such a basic task. Looks nice and all, but it still returns only the type "object", so it doesn't really solve your specific problem.
Also, to address one issue I'm not sure you understand - you've already created the instance, you just return type object. That is why you can't call any specific methods on this object, because first you have to cast it to something, that actually has that method and make sure the cast can be done (inheritance etc).
If interface solution (see other answers) is enough, don't look at this answer. When you can't use common base class / interface and you still want call members, you can use solution with is keyword (and check types). Instead of writing many ifs for each case, you can use fluent API:
object obj = this.getConstructorclass();
obj.StronglyInvoke()
.When<int>(value => Console.WriteLine("Got {0} as int", value))
.When<string>(value => Console.WriteLine("Got {0} as string", value))
.OnFail(() => Debug.Write("No handle."))
.Invoke();
Solution:
public class GenericCaller
{
private IList<GenericInvoker> invokers = new List<GenericInvoker>();
private readonly object target;
private Action failAction;
public GenericCaller(object target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
this.target = target;
}
public GenericCaller OnFail(Action fail)
{
this.failAction = fail;
return this;
}
public GenericCaller When<T>(Action<T> then)
{
if (then == null)
{
throw new ArgumentNullException("then");
}
var invoker = new GenericInvoker<T>(this.target, then);
this.invokers.Add(invoker);
return this;
}
public void Invoke()
{
if (this.invokers.Any(invoker => invoker.Invoke()))
{
return;
}
if (this.failAction == null)
{
throw new InvalidOperationException("Handler not found");
}
this.failAction();
}
public abstract class GenericInvoker
{
protected readonly object target;
protected GenericInvoker(object target)
{
this.target = target;
}
public abstract bool Invoke();
}
public class GenericInvoker<T> : GenericInvoker
{
private readonly Action<T> then;
public GenericInvoker(object target, Action<T> then)
: base(target)
{
this.then = then;
}
public override bool Invoke()
{
if (this.target.GetType() == typeof(T))
{
this.then((T)this.target);
return true;
}
return false;
}
}
}
public static class Extensions
{
public static GenericCaller StronglyInvoke(this object o)
{
return new GenericCaller(o);
}
}
Remeber - it would be more elegant to use common interface (as other answers say) - my is only alternative way.
Declare your variable as dynamic
dynamic objcls = getconstrorclass();
Using this the will be determined at run-time, whatever the getconstrorclass method returns. You can access any member of the type and you won't get any error at compile-time. But if you try to access a member which doesn't exists you will get a RuntimeBinderException at runtime.
I would recommend using an interface and restricting the classes that you can instantiate this way to only those that implement the interface.
public interface IMyInterface
{
void callclass();
}
public <T> getConstructorClass()
{
T instance;
Type type = Type.GetType("test1");
// instance will be null if the object cannot be cast to type T.
instance = Activator.CreateInstance(type) as T;
return T;
}
IMyInterface objcls = getConstructorClass<IMyInterface>();
if(null != objcls)
{
objcls.callclass();
}
not sure what you want to achieve in the end, but this looks like a job for "Dependency Injection" - here is a nice sample using autofac
Let's say, for example, we have a method, which for sake of argument we'll call MethodOne;
public void MethodOne()
{
//do stuff.
}
Now let's say we want to create an optional peramater, and we might decide to create another method with the same name, that takes different overloads, for example;
public void MethodOne()
{
//do stuff.
}
public void MethodOne(bool checkVar)
{
if(checkVar)
{
//do stuff
}
else
{
//do other stuff
}
}
So now we've got a method which has two different overload combinations(?). Is this, in practise, better than having one method, and just checking whether the optional overload is null or contains information, for example;
public void MethodOne(int? testVar)
{
if(testVar != null)
{
//do stuff
}
}
This may seem trivial with just one overload, but imagine that i've got 5 variables i want to pass through, would i create 5 methods, same name with different overloads, or just one method and check the passed variables?
There are a few workarounds for this. You could, for example, use an enumerator and an Object array as second parameter which contains real parameter values so that you know what to do with data by switching the enumerator... or you could just declare 5 Object parameters and then check for their type in a switch, box them accordingly and proceed. But both options are very bad practices.
I suggest you to stick on different overloads:
public void MethodOne(Boolean value)
{
// Process the value...
}
public void MethodOne(Int32 value)
{
// Process the value...
}
public void MethodOne(Int32 value, String text)
{
// Process the value and the text...
}
// And so on...
Or default data in parameter declarations:
public void MethodOne(Int32 integer = 1, String text = "hello", ...)
{
// Process everything inside the method...
}
Or parametrized methods (if every object type has a common processing):
public void MethodOne(params Object[] parameters)
{
for (int i = 0; i < parameters.Length; ++i)
// Check type of parameter and process the value...
}
Or methods bubbling if your design allows it (which is my favorite one as the first one is just producing a lot of code redundancies and the second one may be sometimes confusing for you or other developers working with you):
public void MethodOne(Int32 value)
{
MethodOne(value, "hello");
}
public void MethodOne(Int32 value, String text)
{
// Process everything inside the method...
}
What you can do is use optional arguments:
public void MethodOne(int testVar = 0)
{
if(testVar != 0)
{
//do stuff
}
}
You generally bubble down on overloads like this:
public void MethodOne()
{
MethodOne(1)
}
public void MethodOne(int testVar)
{
MethodOne(testVar, "test")
}
public void MethodOne(int testVar, string testString)
{
MethodOne(testVar, testString, null)
}
public void MethodOne(int testVar, string testString, object testObject)
{
// Do your actual code here
}
This would be equivalent to
public void MethodOne(int testVar = 1, string testString = "test", object testObject = null)
{
// Do your actual code here
}
But usually you should prever overloads over default parameters. Also, by 'bubbling down' like in my example you avoid having redundant code or redundant 'default parameters'
As the number of arguments increase, I wouldn't want to look through a method's nested if/else logic to determine what arguments are being used or not. It's hard to read, understand, maintain and can lead to bugs. Use overloads and keep your methods concise, lean and maintainable.
Using C# 4.0, is there a way to allow a method (without creating an overload) to accept a string or an int and then allow me to detect what type was passed in?
Since you're using C# 4.0, you can write a generic method. For example:
void MyMethod<T>(T param)
{
if (typeof(T) == typeof(int))
{
// the object is an int
}
else if (typeof(T) == typeof(string))
{
// the object is a string
}
}
But you should very seriously consider whether or not this is a good idea. The above example is a bit of a code smell. In fact, the whole point of generics is to be generic. If you have to special-case your code depending on the type of the object passed in, that's a sign you should be using overloading instead. That way, each method overload handles its unique case. I can't imagine any disadvantage to doing so.
Sure you can! An example of this is
public void MyMethod(object o)
{
if (o.GetType() == typeof(string))
{
//Do something if string
}
else if (o.GetType() == typeof(int))
{
// Do something else
}
}
You can wrap string and int in some wrapper with marker interface and pass them to a method.
Something like this
interface IMyWrapper<T> { T Value {get; }}
public class StringWrapper: IMyWrapper<string> { ... }
public class IntWrapper: IMyWrapper<int> { ... }
void MyMethod<T>(IMyWrapper<T> wrapper)
{
}
I would think a method overload would be a straightforward solution, if you want to stay away from stuff like reflection or checking types.
public void MethodName(string foo)
{
int bar = 0;
if(int.tryparse(foo))
return MethodName(bar);//calls int overload
}
I have a method that I'm writing that is calling another overloaded method inside it. I'd like to only write one outer method, since the parameter to the outer method is being passed to the inner one. Is there a way to do this?
I tried using generics, but I don't know enough about this so it isn't working:
public void OuterMethod<T>(T parameter)
{
InnerMethod(parameter); // InnerMethod accepts an int or a string
}
I know that I can do this:
public void OuterMethod(string parameter)
{
InnerMethod(parameter);
}
public void OuterMethod(int parameter)
{
InnerMethod(parameter);
}
But I'd rather do this the right way instead of copying/pasting code. What's the best way to accomplish this?
You can do this in C++ but not in C# (unless the inner method can also be generic instead of overloaded).
Alternatively (if you won't take 'no' for an answer), you can do a run-time switch on type, like for example ...
public void OuterMethod(object parameter)
{
if (parameter is int)
InnerMethod((int)parameter);
else if (parameter is string)
InnerMethod((string)parameter);
else
throw new SomeKindOfException();
}
... but obviously this is a run-time, not a compile-time check.
But I'd rather do this the right way instead of copying/pasting code.
You can also write software to write your outer methods (e.g. using System.CodeDom classes) instead of writing them by hand, but this is probably more trouble than it's worth.
Like the others said, you can't really do what you are trying to do and the option you stated in your question is the best bet.
You would actually have to convert the value if you use the generic. Otherwise you can downcast by accepting an Object as ChrisW suggests.
public void OuterMethod<T>(T parameter)
{
T temp = parameter;
if (temp is string )
InnerMethod(Convert.ToString(temp));
if (temp is int)
InnerMethod(Convert.ToInt32(temp));// InnerMethod accepts an int or a string
}
Here is a link to the overview of Generics: http://msdn.microsoft.com/en-us/library/ms172193.aspx
From your description this seems like over-optimization.
How about:
public void OuterMethod(string parameter)
{
InnerMethod(parameter);
}
public void OuterMethod(int parameter)
{
InnerMethod(parameter**.ToString()**);
}
You can use a dynamic type to defer the overload resolution until run-time.
public void OuterMethod(dynamic parameter)
{
InnerMethod(parameter);
}
public void InnerMethod(int parameter) { }
public void InnerMethod(string parameter) { }
Caveat Expressions of type dynamic are not resolved or type checked by the compiler. And there might be a performance penalty as well.
If OuterMethod always calls InnerMethod, and InnerMethod only accepts an int or string, then OuterMethod<T> doesn't make any sense.
If the only difference is that one calls InnerMethod(int) and the other calls InnerMethod(string) you could do something like this:
public void OuterMethod(string parameter)
{
InnerMethodA(parameter);
}
public void OuterMethod(int parameter)
{
InnerMethodA(parameter);
}
private void InnerMethodA(object parameter)
{
// Whatever other implementation stuff goes here
if (parameter is string)
{
InnerMethodB((string) parameter);
}
else if (parameter is int)
{
InnerMethodB((string) parameter);
}
else
{
throw new ArgumentException(...);
}
}
private void InnerMethodB(string parameter)
{
// ...
}
private void InnerMethodB(int parameter)
{
// ...
}
Ok I have a similar situation, its an access control method in my business logic.
There is a save function that could be applied to any of my persistance layer objects.
so that looks like this
public static Save<T>(AccessControl.User user,T entity) where T:PersistanceLayerBaseClass
{
if(CanWrite(user, entity))
{
entity.save();
}
else
{
throw new Exception("Cannot Save");
}
}
How ever I have some custom code for certain entities in terms of Access Control so I wrote the following, it looks for a method more suitable to the question using System.Reflection, "can this entity be written by this user?"
public static Boolean CanWrite<T>(AccessControl.User user, T entity) where T : PersistanceLayerBaseClass
{
int? clubId = null;
MethodInfo methodInfo = entity.GetType().GetMethod("CanWrite", new Type[] { typeof(AccessControl.User), entity.GetType() });
if(methodInfo != null)
{
return (Boolean)methodInfo.Invoke(null, new object[] { user, entity }) ;
}
else
{
//generic answer
}
return HasRole(user.UserID, "Administrator") || (clubId.HasValue && user.MemberObject.ClubId == clubId.Value && HasRole(user.UserID, "AdministerClub"));
}
Now every time I add or remove a method, I only have to add or remove it in one place