Call a generic method ensuring where - c#

I have a generic method, on the base of T type I need to call a stricter generic method, how can I do it without reflections? In the example I used as that is obviusly wrong
public T foo1<T>()
{
if(T is IMyInterface)
{
return SpecificMethod<T as IMyInterface>();
}
}
private T SpecificMethod<T>() where T : IMyInterface
{
// IMyInterface specific implementation
}
private T GenericMethod<T>()
{
// something generic to do
}

You can approach it this way:
public interface IMyInterface { }
public T Foo1<T>()
{
if (typeof(T) == typeof(IMyInterface))
{
return (T)SpecificMethod<IMyInterface>();
}
return default(T);
}
private T SpecificMethod<T>() where T : IMyInterface
{
return default(T);
}
private T GenericMethod<T>()
{
return default(T);
}
What you asked for, can't just be done.

Related

How to get the type of an object and pass it as a parameter in C#

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))){
}
}

Unity container, resolve to an abstract class level and not top Interface

I have the following code defined in terms of hierarchy -
public interface ISomeInterface
{
bool DoSomething();
}
public abstract class AbsActualWorker : ISomeInterface
{
public bool DoSomething()
{
Console.WriteLine("DoSomething");
throw new Exception("throwing exception for the sake of it!");
}
public abstract bool DoSomething2();
}
public class ActualWorker : AbsActualWorker
{
public override bool DoSomething2()
{
Console.WriteLine("DoSomething2");
Thread.Sleep(1000);
return true;
//throw new Exception("throwing exception for the sake of it!");
}
}
Im trying to resolve to the ActualWorker level and execute its DoSomething2
var container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<AbsActualWorker, ActualWorker>();
container
.RegisterType<ISomeInterface, ActualWorker>(new Interceptor(new InterfaceInterceptor()),
new InterceptionBehavior(new MyLoggerBehavior())
);
var instance = container.Resolve<ISomeInterface>();
if (instance != null)
{
instance.DoSomething();
}
Code happily resolves and can call
instance.DoSomething();
When I cast instance to ActualWorker Im getting null. Id like to use call DoSomething2.
public class MyLoggerBehavior : IInterceptionBehavior
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var returnValue = getNext()(input, getNext);
if (returnValue.Exception != null)
{
Console.WriteLine("Exception occurred!!");
}
else
{
Console.WriteLine("Method {0} returned {1}", input.MethodBase, returnValue.ReturnValue);
}
return returnValue;
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute
{
get { return true; }
}
}
Your problem is in interceptor. Due to
container.RegisterType<ISomeInterface, ActualWorker>(new Interceptor(new InterfaceInterceptor()), new InterceptionBehavior(new MyLoggerBehavior()));
You get for ISomeInterface not ActualWorker type but a wrappertype that realize ISomeInterface. This type cannot be casted to ActualWorker.
If you work with Dependency injection you should not call methods that is not in public interface that you inject. If you need to cast variable of interface to concrete realization it means that you do something wrong.

Why can't I return my object as its' interface?

I have a series of interface definitions, all of which compile (so my objects are composed correctly). The objects instantiate, as expected. However, when I try to return the object from its' underlying factory I get the following error:
ERROR:
Unable to cast object of type
'SampleLibrary.Domain.DataAcessors.Person.SQLDataAccessor' to type
'Common.Contracts.DataAccessors.IDataAccessorModel`2[SampleLibrary.Contracts.Models.IPerson,SampleLibrary.Domain.DataAccessors.Types.SqlServer]'.
Please keep in mind I am trying to return each instance as the IDataAccessor interface.
CODE:
public interface IDataAccessor<I, T>
{
T AccessType { get; }
}
public interface IDataAccessorModel<I, T> : IDataAccessor<I, T>
{
I Instance { get; }
IResult<string> Get(I instance);
IResult<string> Add(I instance);
IResult<string> Update(I instance);
IResult<string> Delete(I instance);
}
public class SQLDataAccessor : IDataAccessorModel<IPerson, IAccessType>
{
internal SQLDataAccessor(IResult<string> result)
{
_connectionString = "";
_result = result;
}
private readonly string _connectionString;
private IResult<string> _result;
public IAccessType AccessType { get { return new SqlServer(); } }
public IPerson Instance { get; private set; }
public IResult<string> Add(IPerson instance)
{
Instance = instance;
return _result;
}
public IResult<string> Get(IPerson instance)
{
Instance = instance;
return _result;
}
public IResult<string> Delete(IPerson instance)
{
Instance = instance;
return _result;
}
public IResult<string> Update(IPerson instance)
{
Instance = instance;
return _result;
}
}
public class FactoryDataAccess : IFactoryDataAccess
{
internal FactoryDataAccess() { }
public IDataAccessor<I, T> Create<I, T>()
{
var model = typeof(I);
var target = typeof(T);
if (model.IsAssignableFrom(typeof(IPerson)))
{
if (target == typeof(SqlServer)) {
var accessor = new Person.SQLDataAccessor(new Result());
// This next line FAILS!
return (IDataAccessorModel<I, T>)accessor;
}
}
throw new NotSupportedException("Type " + target.FullName + " and Source " + model.FullName + " is not supported.");
}
}
UPDATE:
Please keep in mind that IDataAccessorModel can be used by any desired DataAccess type you wish to define.
SQLDataAccessor implements IDataAccessorModel<IPerson, IAccessType>, so it would work only if <I, T> were <IPerson, IAccessType>. There is no guarantee about that, since the method is generic and I and T could be any type, so the cast fails.
Of course, since you're checking the types of I and T, you know the cast would be valid, but the compiler doesn't. You can trick it like this:
return (IDataAccessorModel<I, T>)(object)accessor;
However, since T has to be SqlServer, it doesn't make sense to make it a generic type parameter. And since I has to implement IPerson, there should be a constraint on it. So the method signature should be:
public IDataAccessor<I, T> Create<T>() where T : IPerson
It work for me if I declare SQLDataAccessor like this:
public class SQLDataAccessor : IDataAccessorModel<IPerson, SqlServer>
{
...
}
You are probably calling it like this
var factory = new FactoryDataAccess();
var da = factory.Create<IPerson, SqlServer>();
i.e. you call it with T being SqlServer. If you declare T as IAccessType in SQLDataAccessor it is not guaranteed that IAccessType would be SqlServer. Therefore the casting error. (However, SqlServer is guaranteed to be IAccessType as it probably implements it.)
SQLDataAccessor is not a generic class, but implements IDataAccessorModel<IPerson, IAccessType> exactly, so your method Create should return IDataAccessor<IPerson, IAccessType>, but you probably called it with other generic types.
Change SqlDataAccessor to:
public class SQLDataAccessor<I, T> : IDataAccessorModel<I, T>
{
internal SQLDataAccessor(IResult<string> result)
{
_connectionString = "";
_result = result;
}
private readonly string _connectionString;
private IResult<string> _result;
public T AccessType { get { return new SqlServer(); } }
public I Instance { get; private set; }
public IResult<string> Add(I instance)
{
Instance = instance;
return _result;
}
public IResult<string> Get(I instance)
{
Instance = instance;
return _result;
}
public IResult<string> Delete(I instance)
{
Instance = instance;
return _result;
}
public IResult<string> Update(I instance)
{
Instance = instance;
return _result;
}
}
You might want to limit I and T to the interfaces, so add a where constraint:
public class SQLDataAccessor<I, T> : IDataAccessorModel<I, T>
where I : IPerson
where T : IAccessType
The way you have it, I could be any type derived from IPerson and T is exactly of type SqlServer, which would cause the cast to fail since SQLDataAccessor implements the IDataAccessorModel with different parameters. You would need to have a more exact cast, such as:
return (IDataAccessorModel<IPerson, IAccessType>)accessor;

I need a common class/interface for any .Net data type

I'm looking for a way to treat ALL .Net datatypes consistently so I can create the pattern below where any type implementing IGetValue<out T> will cast to IGetValue<object>. For some reason, if T is a struct, it doesn't work and I don't understand why. Is there a way I can implement the following pattern??
public interface IGetValue<out T>
{
T Value
{
get;
}
}
public class GetValue<T> : IGetValue<T>
{
public GetValue(T value)
{
_value = value;
}
private T _value;
public T Value
{
get { return _value; }
}
}
class Program
{
static void Main(string[] args)
{
IGetValue<string> GetString = new GetValue<string>("Hello");
IGetValue<int> GetInt = new GetValue<int>(21);
//This works!!!
if (GetString is IGetValue<object>)
{
Console.WriteLine("GetValue<string> is an IGetValue<object>");
}
else
{
Console.WriteLine("GetValue<string> is not an IGetValue<object>");
}
//This doesn't work!!! Why????
if (GetInt is IGetValue<object>)
{
Console.WriteLine("GetValue<int> is an IGetValue<object>");
}
else
{
Console.WriteLine("GetValue<int> is not an IGetValue<object>");
}
Console.ReadKey();
}
}
Edit:
I realize what I'm trying to accomplish here seems vague, but this is part of a larger design whose explanation would be too verbose. What I need is to have all of my IGetValue<T>s to share a common type or interface with a property named "Value" that returns an object. Why is the verbose part.
It doesn't work because generic variance doesn't apply to value types... they have different representations, whereas variance with reference types can happen without the CLR having to perform any conversions.
So for example, you can treat an IEnumerable<string> as an IEnumerable<object>, but you can't treat an IEnumerable<int> as an IEnumerable<object>.
I ended up solving my immediate need by creating a non-generic IGetValue interface and implementing it explicitly in the class. Here's the solution:
public interface IGetValue
{
object Value
{
get;
}
}
public interface IGetValue<out T>
{
T Value
{
get;
}
}
public class GetValue<T> : IGetValue<T>, IGetValue
{
public GetValue(T value)
{
_value = value;
}
private T _value;
public T Value
{
get { return _value; }
}
object IGetValue.Value
{
get { return _value; }
}
}
class Program
{
static void Main(string[] args)
{
IGetValue<string> GetString = new GetValue<string>("Hello");
IGetValue<int> GetInt = new GetValue<int>(21);
if (GetString is IGetValue)
{
Console.WriteLine("GetValue<string> is an IGetValue");
}
else
{
Console.WriteLine("GetValue<string> is not an IGetValue");
}
if (GetInt is IGetValue)
{
Console.WriteLine("GetValue<int> is an IGetValue");
}
else
{
Console.WriteLine("GetValue<int> is not an IGetValue");
}
Console.ReadKey();
}
}

Generic class factory problem

Bellow is simplified version of the code I have:
public interface IControl<T>
{
T Value { get; }
}
public class BoolControl : IControl<bool>
{
public bool Value
{
get { return true; }
}
}
public class StringControl : IControl<string>
{
public string Value
{
get { return ""; }
}
}
public class ControlFactory
{
public IControl GetControl(string controlType)
{
switch (controlType)
{
case "Bool":
return new BoolControl();
case "String":
return new StringControl();
}
return null;
}
}
The problem is in GetControl method of ControlFactory class. Because it returns IControl and I have only IControl<T> that is a generic interface. I cannot provide T because in Bool case it's going to bool and in String case it's going to be string.
Any idea what I need to do to make it work?
Just derive IControl<T> from IControl.
public interface IControl<T> : IControl
{
T Value { get; }
}
UPDATE
If I missunterstood you, and you don't want a non-generic interface, you will have to make the method GetControl() generic, too.
public IControl<T> GetControl<T>()
{
if (typeof(T) == typeof(Boolean))
{
return new BoolControl(); // Will not compile.
}
else if (typeof(T) == typeof(String))
{
return new StringControl(); // Will not compile.
}
else
{
return null;
}
}
Now you have the problem that the new controls cannot be implicitly casted to IControl<T> and you would have to make this explicit.
public IControl<T> GetControl<T>()
{
if (typeof(T) == typeof(Boolean))
{
return new (IControl<T>)BoolControl();
}
else if (typeof(T) == typeof(String))
{
return (IControl<T>)new StringControl();
}
else
{
return null;
}
}
UPDATE
Changed the cast from as IControl<T> to (IControl<T>). This is prefered because it will cause an exception if there is a bug while as IControl<T> silently returns null.
public IControl<T> GetControl<T>()
{
switch (typeof(T).Name)
{
case "Bool":
return (IControl<T>) new BoolControl();
case "String":
return (IControl<T>) new StringControl();
}
return null;
}
Update; corrected a couple of errors in the code. Heres a call to get a class:
IControl<bool> boolControl = GetControl<bool>();
The return type has to be generic, since, well, it is. Think of how you would use this. Returning a strongly typed object obviates the need for a generic factory method.
Even if you could do it, what's the gain of
IControl<bool> boolControl = controlFactory.GetControl("bool");
or, the one that would work,
IControl<bool> boolControl = controlFactory.GetControl<bool>("bool");
over a specific
IControl<bool> boolControl = controlFactory.GetBoolControl("bool");
Either way, you have the switch () at the client side. Either return an object, or have a non-typed IControl interface.

Categories

Resources