Generic inheritance constraint on class parameter fails - c#

public class Test<T>
{
private T something;
public Test<NewT> Cast<NewT>() where T : NewT
{
return new Test<NewT>() { something = this.something };
}
}
VS Error: 'Test.Cast()' does not define type parameter 'T'
Why does this happens?

This is because you can only constrain type parameters that are defined in the method. T is not defined in the method, but in the class, so you can't constrain it like that.
You can, however, make Cast an extension method:
// in some static class
public static Test<NewT> Cast<T, NewT>(this Test<T> test) where T : NewT {
return new Test<NewT>() { something = test.something };
}
This means that something has to be made public, which can sometimes be undesirable. You can alternatively do something like this:
public class Test<T>
{
public T Something { get; private set; }
public Test(T something) {
Something = something;
}
}
// in some static class
public static Test<NewT> Cast<T, NewT>(this Test<T> test) where T : NewT
{
return new Test<NewT>(test.Something);
}

Related

Can not convert type int to T

I run into a compiler error that I am not sure how to resolve it.
Basically, I have a few enum classes described below.
I created abstract classes myTool and myTools deriving from myTool.
The compiler for some reason does not like the way I structured the constructor for MyTools and threw error
CS0030: Can not convert type int to type T.
Please advice me how to resolve this.
public enum TOOLS
{
HAMMER =1,
DRILL = 2,
SCREWDRIVER =3,
VACUUM=4
}
public enum EQUIPMENTS
{
MOWER=1,
TRIMMER=2,
SNOWBLOWER=3
}
public abstract class MyTool
{
protected T _myStuff
int quantity
double price
public MyTool(T t)
{
_myStuff =t;
}
... properties...
}
public abstract class MyTools<T>:myTool<T>
where T:System.Enum
{
protected MyTool<T>[] _myTools;
public MyTool<T> this[int i]=> this._myTools[i];
public MyTools(int count, T t):base(t)
{
_myTools = new MyTools<T>[count];
for (int i=0; i<count;i++)
{
_myTools[i]=(T)(i+1);
}
}
}
You can convert an int into a generic type constrained as System.Enum like this:
T enumValue = (T)Enum.ToObject(typeof(T), intValue);
or simply
T enumValue = (T)(object)intValue;
You can use generic type converter
public static class TConverter
{
public static T ChangeType<T>(object value)
{
return (T)ChangeType(typeof(T), value);
}
public static object ChangeType(Type t, object value)
{
TypeConverter tc = TypeDescriptor.GetConverter(t);
return tc.ConvertFrom(value);
}
public static void RegisterTypeConverter<T, TC>() where TC : TypeConverter
{
TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC)));
}
}
and usage:
TConverter.ChangeType<T>(intValue);
it is from here: https://stackoverflow.com/a/1833128/2286743

Passing in member functions as delegate parameters

I have a base class, whose ctor takes a delegate as a parameter and a class which inherits from it.
The following works just fine:
class Base
{
public Base(Func<bool> func)
{
}
}
class Sub : Base
{
public Sub()
: base(() => true)
{
}
public Sub(int i)
: base(() => { return true; })
{
}
}
How can I pass an instance function as a parameter?
Compiler complains with error "An object reference is required for the non-static field, method, or property".
What I would like to have is this:
class Sub : Base
{
public Sub()
: base(Func)
{
}
private bool Func()
{
return true;
}
}
It would work if Func was a static method. But I'd like to use instance members inside the function.
How could I accomplish this?
As commented this looks to me like an X Y problem to me, and seems like a flawed design,
can you change your base class to just call a virtual method and just override it ?
class Base
{
public Base()
{
}
public virtual bool func() {return false};
}
class Sub : Base
{
public Sub()
{
}
public override bool func()
{
return true;
}
}
also you can read more about it at https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual

Check if generic parameter of a class implements an interface

I have a following generic class:
public class SearchResult<T>
{
public int ResultCount { get; set; }
public IEnumerable<T> Result { get; set; }
}
I also have a Bird class, which implements IFlyble interface:
public class Bird : IFlyable
{
public void Fly() {}
}
public interface IFlyable
{
void Fly();
}
I also have a variable res of type object.
How do I check if res is a SearchResult<IFlyable> ?
I tryied this way:
if (res.GetType().IsAssignableFrom(typeof(SearchResult<IFlyable>)))
{
///
}
And this way:
if(res is SearchResult<IFlyable>)
{
///
}
But it does not seems to work.
The problem you are having is probably due to the fact that SearchResult<Bird> is not convertible to SearchResult<IFlyable> because SearchResult<T> is invariant in T.
C# only admitís generic type variance in interfaces and delegates. You need to define an ISearchResult<> interface that is covariant in its generic type.
In your case, if it’s accepatable that T Is only used as an output you could define such interface as follows:
public interface ISearchResult<out T>
{
int ResultCount { get; }
IEnumerable<T> Result { get; }
}
And now a ISearchResult<Bird> is a ISearchResult<IFlyable> because you’ve given the compiler enough information so that it can verify that the conversion is in fact safe
You can also try this using reflection, which also works and no need to create another interface.
static void Main()
{
var sr = new SearchResult<Bird>();
Console.WriteLine(IsSearchResultIFlyable(sr.GetType())
? "sr is SearchResult<IFlyable>"
: "sr is Not SearchResult<IFlyable>");
Console.ReadLine();
}
public static bool IsSearchResultIFlyable(Type t)
{
if (!t.IsGenericType) return false;
if (t.GetGenericTypeDefinition() != typeof(SearchResult<>)) return false;
var gr = t.GetGenericArguments();
return gr.Length == 1 && typeof(IFlyable).IsAssignableFrom(gr[0]);
}

Return the generic object, from a generic object

public class ClassWithGeneric<T>
{
}
public class SecondClassWithGeneric<U>
{
public void getNestedObject()
{
//How do I get the type of object T?
}
}
public class TestProgram
{
var nestedGenerics = new SecondClassWithGeneric<ClassWithGeneric<ObjectToLoad>>;
}
public class ObjectToLoad
{
}
The question is how do I get the type of object T? in this case it would return "ObjectToLoad".
Not very clear but probably:
public class SecondClassWithGeneric<U, T>
where U : ClassWithGeneric<T>
{
public T getNestedObject()
{
//How do I get the type of object T?
}
}
or maybe
public class SecondClassWithGeneric<U, T>
{
public ClassWithGeneric<T> getNestedObject()
{
//How do I get the type of object T?
}
}
This should give you the type ObjectToLoad but it's also highly prone to error.
public class SecondClassWithGeneric<U>
{
public void getNestedObject()
{
var type = typeof(U).GetGenericArguments()[0];
}
}

C# - How can I have an type that references any object which implements a set of Interfaces?

How can I have a type reference that refers to any object that implements a set of interfaces?
For example, I can have a generic type like this:
Java:
public class Foo<T extends A & B> { }
C#
public class Foo<T> where T : A, B { }
That's how to have a class-wide generic type. However, I'd like to simply have a data member which references any object that extends a given set of interfaces.
Example:
public class Foo
{
protected <? extends A, B> object;
public void setObject(<? extends A, B> object)
{
this.object = object;
}
}
If it's possible to have this sort of type syntax, how could I do it in both Java and C#?
I realize I can just create another interface that extends all desired interfaces. However, I don't see this as optimal, as it needlessly adds another type whose sole purpose is to get around syntax. Granted this is a very minor issue, but in terms of elegance it's a bit galling.
My Java has become a bit rusty through 2years of inactivity.
Here's my C# approach: (see https://ideone.com/N20xU for full working sample)
public class Foo
{
private IInterface1 _object; // just pick one
public void setObject<T>(T obj)
where T : IInterface1, IComparable<T>, IEtcetera
{
// you now *know* that object supports all the interfaces
// you don't need the compiler to remind you
_object = obj;
}
public void ExerciseObject()
{
// completely safe due to the constraints on setObject<T>
IEtcetera itf = (IEtcetera) _object;
// ....
}
As far as I know, You cannot create a variable with constraints on it, you can only create a variable of a given type. The type has the constraints. This means you have to define a type that has the constraints you desire, then create the variable with that type.
This seems logical to me, and I don't see why you find it "galling" to have to define a type for what you need.
In C#, you can use a tuple to store the value in a kind of superposition:
public class Foo {
private Tuple<IA, IB> junction;
public void SetValue<T>(T value) where T : IA, IB {
junction = Tuple.Create<IA, IB>(value, value);
}
}
You can also have a specialized class to enforce the constraint that both values reference the same object:
public class Junction {
public IA A { get; private set; }
public IB B { get; private set; }
private Junction() { }
public static Junction Create<T>(T value) where T: IA, IB {
return new Junction {
A = value,
B = value
};
}
}
public class Foo {
private Junction junction;
public void SetValue<T>(T value) where T : IA, IB {
junction = Junction.Create(value);
}
}
In Java, a wildcard would simplify things a little:
class Junction<E extends A & B> {
private final E value;
public Junction(E value) {
this.value = value;
}
public E getValue() {
return value;
}
}
class Foo {
private Junction<?> junction;
public <E extends A & B> void setValue(E value) {
junction = new Junction<E>(value);
}
}
Or you can have aliases to the same value (C#, but also applicable to Java):
public class Foo {
private IA a;
private IB b;
public void SetValue<T>(T value) where T : IA, IB {
a = value;
b = value;
}
}
I don't see any problem with simply stating the constraints as a private interface:
class Foo
{
interface R : I1, I2 { }
R _object;
void setObject(R r) { _object = r; }
}
Here's the best I could come up with (but still not an optimal solution)
public class Foo
{
private TypeWrapper<IInterface1,IInterface2> _object;
public void setObject<T>(T obj)
where T : IInterface1, IInterface2
{
_object = new TypeWrapper<IInterface1, IInterface2>();
_object.SetObject(obj);
var val = _object.Get(h => h.c);
Console.WriteLine(val);
_object.Do(h => h.c = 25);
val = _object.Get(h => h.c);
Console.WriteLine(val);
_object.Do(h => h.someF());
}
}
public class TypeWrapper<TType, TTypeTwo>
{
private Object m_Obj;
public void SetObject<T>(T obj) where T : TType, TTypeTwo
{
m_Obj = obj;
}
public T Get<T>(Func<TType, T> action)
{
return (T)action((TType)m_Obj);
}
public T Get<T>(Func<TTypeTwo, T> action)
{
return (T)action((TTypeTwo)m_Obj);
}
public void Do(Action<TTypeTwo> action)
{
action((TTypeTwo)m_Obj);
}
public void Do(Action<TType> action)
{
action((TType)m_Obj);
}
}
public class myClass : IInterface1, IInterface2 {
public int t {get;set;}
public int c {get;set;}
public void someF() { Console.WriteLine("Fired"); }
}
public interface IInterface1 {
int t { get;set;}
void someF();
}
public interface IInterface2 {
int c { get;set; }
}
You're going to have to work on the object through the Get and Do methods, but it'll work with intellisense and throw compile time errors if the interfaces change.

Categories

Resources