Casting generic class to dynamic type - c#

I have a generic class that I want to cast to a dynamic generic, but I get a Cannot convert type MyGeneric1<MyTypedClass1> to MyGeneric1<dynamic> error message. Is this kind of cast to dynamic possible, and if so then please explain.
Here is where I try to cast a typed MyGeneric1 generic class into a dynamic MyGeneric1.
public static class Extensions
{
public static MyGeneric1<dynamic> ToDynamic(this MyGeneric1<MyTypedClass1> myObj1)
{
return (MyGeneric1<dynamic>)myObj1;
}
}
The MyGeneric1 class is defined like so:
public class MyGeneric1<T> : DynamicObject { // Code here ... }
The MyTypedClass1 class is defined like so:
public class MyTypedClass1: DynamicObject { // Code here ... }

MyTypedClass1 is assignable to dynamic, as it inherits from it. But you cannot simply cast generic classes, when they have different generic arguments, even when arguments themselves are valid for assigning (as MyTypedClass1 and dynamic ).
But, you can create new instance with proper generic type and assign value for it:
public class MyTypedClass1 : DynamicObject
{
public string SomeProperty { get; set; }
}
public class MyGeneric<T> : DynamicObject
{
// just some property to get the idea
public T Value { get; set; }
}
public static class MyGenericExtensions
{
public static MyGeneric<dynamic> ConveretGeneric(this MyGeneric<MyTypedClass1> argument)
{
return new MyGeneric<dynamic>()
{
// here you need to assign all needed properties
Value = argument.Value
};
}
}

Related

How i access dynamic class property in generic class by c#?

I wanna access my passed dynamic class property in generic class. How can i do?
My class property is here.
public class Test
{
[DataMember]
public string Body { get; set; }
[DataMember]
public string Header { get; set; }
}
I sent 'Test' class to Class1.
public class Class1
{
public static T Fill<T>(T myClass)
{
//how can i access Test class property in here?
myClass.Header ????
return obj;
}
}
I passed class to generic method as follows.
var x = Class1.Fill(new Test());
Please help. Thank you.
If you really need dynamic and sure there's a Header string property then you can do this:
public class Class1
{
public static dynamic Fill(dynamic myClass)
{
myClass.Header = "222";
...
...
return myClass; // or whatever
}
}
But, if you ended up with that, i would recommend that you review your desgin.
If the generic class is always derived from Test you can use a type constraint to have access to the properties of the class:
public static T Fill<T>(T myClass) where T: Test
{
myClass.Header //Will work
return obj;
}
If the class is not derived from test, you will have to use reflection to have access to the property. Using simple reflection you can do something like :
public static T Fill<T>(T myClass) where T: Test
{
typeof(T).GetProperty("Header").GetValue(myClass); // Get the value
return obj;
}

Polymorphism while iheriting generic class [duplicate]

This question already has answers here:
Convert List<DerivedClass> to List<BaseClass>
(13 answers)
Closed 5 years ago.
Let's consider that there is an abstract base class and one, or more child classes:
public abstract class BaseInnerClass
{
public int Id { get; set; }
}
public class ConcreteInnerClass : BaseInnerClass
{
public string Name { get; set; }
}
Then, let's assume there is a generic abstract class that has a property of above abstract class type:
public abstract class GeneriAbstractTestClass<T> where T : BaseInnerClass
{
public T InnerClass { get; set; }
}
Then let's make a class that inherits from the class above:
public class ConcreteTestClass : GeneriAbstractTestClass<ConcreteInnerClass>
{
public string ConcreteString { get; set; }
}
So now everything is prepared to ask a question ;) Why it is not possible to do it:
//cannot convert initializer type
GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
while this is allowed:
//ok
BaseInnerClass baseInner = new ConcreteInnerClass();
What's the difference between this two assignments?
This has nothing to do with abstract classes. A simpler example would be
List<BaseInnerClass> base = new List<ConcreteInnerClass>
The fact that type A is derived from type B does not imply that type C<A> is derived from type C<B>. Your example is a little bit more complicated, but it can be explained using the same logic.
Note that you can define another concrete type:
public class EvilConcreteInnerClass : BaseInnerClass
{
}
If what you wanted was possible, then the following would work:
GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
genericClass.InnerClass = new EvilConcreteInnerClass(); // OK, because the compiler sees `T` as `BaseInnerClass`
genericClass variable points to an object whose T generic parameter is ConcreteInnerClass, so assigning EvilConcreteInnerClass to the property would result in a run-time exception.
Actually. You can do this. But you need to specify interface with covariant out T generic, because it is type safe to make those casts.
Example
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
var a = new Generic<Concrete>();
IGeneric<Base> c = new Generic<Base>();
c = a;
}
}
public interface IGeneric<out T> where T: Base
{
T Inner { get; }
}
public class Generic<T> : IGeneric<T>
where T : Base
{
public T Inner { get; set; }
}
public class Concrete : Base
{
}
public class Base
{
}
}
Delegates also not restricted if they specify covariant out generic templates.
It means those casts you want is OK as long as you use readonly generic properties. So, like #Kapol said and provided you example why it is not type safe to allow setters on properties or pass T into function.
Summary
Use ReadOnly interfaces if you want to use those kinds of casts.

Returning Unknown Type Without Generics

In my abstract base class AbstractType, I have an abstract auto-implemented property Value of unknown type. All my derived classes implement this property with their own types, such string or double. Normally, I know you would just make it AbstractType<T> and have the property be T Value { ... }. However, I don't have the ability to use generics in this case. In AbstractType, I'm trying to implement a method that returns a new derived class from AbstractType, so if I use generics, the caller has to know the type. If I make Value type object, then the caller has to wrap the object to the correct type - very inconvenient type/instance checking.
Here's what my class structure looks like (the method is simplified for the sake of demonstration):
abstract class AbstractType
{
public abstract ??? Value { get; set; }
AbstractType FromValue(int i)
{
if (i == 0)
return new NumberType();
else
return new StringType();
}
}
class NumberType : AbstractType
{
public override double Value { get; set; }
}
class StringType : AbstractType
{
public override string Value { get; set; }
}
Is there any way to do this without using generics?

How to specify in C# generics such T that is constructible from string? (generic type constraint)

I want to specify required default constructrion options for my T:
public interface IParameter<T> /* where T : T(string) */ {
T Value { get; set; }
}
so I would be able to construct it from given string if passible like this:
Value = "bla";
or at least like this:
Value = new T("bla");
So how to specify in C# generics such T that is constructible from string?
Unfortunately, that constraint is not legal. Only the parameterless constructor constraint is allowed:
where T : new()
Unfortunately, C# does not offer arbitrary constructor signature restrictions for generic parameters. Only a restricted number of constraints are supported, the closest one of which is the new constraint. However, it serves only for enforcing a parameterless constructor.
You can, however, work around this drawback by working with a factory object that takes a string and returns a T. First, define an interface for such factory objects:
public interface IFactory<T>
{
T Create(string str);
}
Subsequently, you can use that factory type in your interface:
public interface IParameter<TFactory, T>
where TFactory : IFactory<T>
{
T Value { get; set; }
}
If you want to be able to instantiate the factories at will, you can require them to have a parameterless constructor:
public interface IParameter<TFactory, T>
where TFactory : new(), IFactory<T>
{
T Value { get; set; }
}
Then, you could use a generic method to instantiate a T based on a string, e.g. as an extension method for your interface:
public static class ParameterUtilities
{
public static void AssignValue<TFactory, T>(this IParameter<TFactory, T> prm, string str)
where TFactory : new(), IFactory<T>
{
var factory = new TFactory();
prm.Value = factory.Create(str);
}
}
As an example of how to use this, let's assume the variable myPrm is an instance of that implements your IParameter interface with appropriate type arguments. You can then invoke something like this:
myPrm.AssignValue("Hello, World!");
You can't, because in generic type constraints you can't say that the type must have a specific constructor (only that it must have a parameterless constructor) nor say that it must have specific methods/operators.
BUT
public interface IFromString<T>
{
void DeserializeFromString(string str);
}
public class MyType : IFromString<MyType>
{
public int Value;
public void DeserializeFromString(string str)
{
Value = int.Parse(str);
}
}
public interface IParameter<T> where T : IFromString<T>, new()
{
T Value { get; set; }
}
public class Parameter<T> : IParameter<T> where T : IFromString<T>, new()
{
T Value { get; set; }
public void Load(string str)
{
Value = new T();
Value.DeserializeFromString(str);
}
}
A classical example... an interface that says that a type can be deserialized from (something) (xml very often :-) )
Use:
Parameter<MyType> parameter = new Parameter<MyType>();
parameter.Load(someStringLoadedFromSomewhere);
You can't specify a constructor in an interface. Depending on your requirements you could use an abstract class:
Pseudo code as not at machine with VS:
public abstract class BaseParameter<T>
{
public abstract void BaseParameter(string something);
T Value { get; set; }
}

Using base objects as parameters in a generic function

I'm trying to implement a helper method using generics (C# / 3.5)
I've a nice structure of classes, with base classes like so:
public class SomeNiceObject : ObjectBase
{
public string Field1{ get; set; }
}
public class CollectionBase<ObjectBase>()
{
public bool ReadAllFromDatabase();
}
public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{
}
And I wish to retreive collection using a generic method like so:
public class DAL
{
public SomeNiceObjectCollection Read()
{
return ReadFromDB<SomeNiceObjectCollection>();
}
T ReadFromDB<T>() where T : CollectionBase<ObjectBase>, new()
{
T col = new T();
col.ReadAllFromDatabase();
return col;
}
}
This doesn't build, with
Error 66 The type 'SomeNiceObjectCollection' cannot be used as type parameter 'T' in the generic type or method 'ReadFromDB<T>'. There is no implicit reference conversion from 'SomeNiceObjectCollection' to 'CollectionBase<ObjectBase>'.
The SomeNiceObjectCollection object IS a CollectionBase, a CollectionBase to be exact. So how I can get this to work?
C# doesn't support casting between list types (covariance).
Your best bet to support this pattern would be to introduce an interface for the ReadAllFromDatabase method so you are not relying on a generic collection:
public class SomeNiceObject : ObjectBase
{
public string Field1{ get; set; }
}
public interface IFromDatabase
{
bool ReadAllFromDatabase();
}
public class CollectionBase<ObjectBase>() : IFromDatabase
{
public bool ReadAllFromDatabase();
}
public class SomeNiceObjectCollection : CollectionBase<SomeNiceObject>
{
}
public class DAL
{
public SomeNiceObjectCollection Read()
{
return ReadFromDB<SomeNiceObjectCollection>();
}
T ReadFromDB<T>() where T : IFromDatabase, new()
{
T col = new T();
col.ReadAllFromDatabase();
return col;
}
}
In C# 3.0 this is not possible, but with C# and .NET 4.0 with covariance and contravariance, this might be possible.
Think about it, you're taking a collection containing a derived object, and trying to temporarily treat it as a collection of the base object. If this was allowed, you could insert base objects into the list, which would not be of the derived object.
Here, an example:
List<String> l = new List<String>();
List<Object> o = l;
l.Add(10); // 10 will be boxed to an Object, but it is not a String!

Categories

Resources