Can I pass T to a class constructor
I have a class such as:
public MyClass
{
public myEnumType Status {get;set;}
public DataTable Res开发者_Go百科ult{get;set;}
}
Because DataTables suck I want to implement an object orientated approach. However I have existing code such as:
public interface IData
{
MyClass AddData(int i);
MyClass GetData(string Tablename);
}
I would like to use this interface but instead of returning a DataTable I want to return an object of some sort eg/Person class.
I did think of creating a new class that inherited MyClass like so:
public MyInheritedClass<T> : MyClass
{
public new T Result{get;set;}
}
However whenever you get data from a class that implements the interface you will have to cast the result of the methods from MyClass to MyInheritedClass. So I was wondering if there was a way of using the existing MyClass to put a constructor in that passes a generic type so I end up with something like
public MyClass
{
public MyClass(T MyObjectOrientatedClass)
{
MyOOClass = MyObjectOrientatedClass;
}
public myEnumType Status {get;set;}
public DataTable Result{get;set;}
public T MyOOClass {get;set;}
}
In C#, the types of expressions are determined by the types of their constituent pieces at compile time. This means something like your last example (where the type of the property is unknowable just by knowing the type of the class) can't work.
Imagine if that class definition compiled. Then you have this problem:
// What would you use as the type of this variable?
??? val = GetMyClassFromSomewhere().MyOOClass;
Sure you could use object
, but then you wouldn't know anything about the property value, so you'd have to cast before you could do anything with it anyway.
Addressing your original issue, it is possible (with a few rough edges) to extend your existing types in a compatible fashion by deriving a new generic interface from your existing IData
interface:
public interface IData<T> : IData
{
new MyInheritedClass<T> AddData(int i);
new MyInheritedClass<T> GetData(string Tablename);
}
You can't refer to a generic type parameter without declaring it in the pointy brackets, so you'll either have to have a IData<T>
and/or MyClass<T>
type, in which case you won't need to specify it as a parameter to the constructor.
If you can't change those types you can still avoid explicit casting by using dynamic dispatch. Overload a method with the different subtypes and use a dynamic expression to defer the method resolution to runtime, and it'll be automatically cast to the subtype for you:
void DoSomethingWith(Person p) { ... }
void DoSomethingWith(AnotherClass x) { ... }
void DomSomtheingWithMyInheritedClass(MyClass x)
{
DoSomethingWith((dynamic) x.Result);
}
Why not create a generic interface like
public interface IData<T>
{
T AddData(int i);
T GetData(string Tablename);
}
we can then even have a generic implementation:
public class MyGenericClass<T> : IData<T>
{
}
While it is a somewhat horrible idea, as long as what you wanted to put into T can be boxed into MyClass
, you could write a method like...
public T GetResult<T>() where T : MyClass
{
return (T)Result;
}
Pretty gross, but it would allow you to "encapsulate" the cast. In reality, though, we're talking about the difference between...
var result = (DerivedMyClass)obj.Result;
...and...
var result = obj.GetResult<DerivedMyClass>();
I'm not sure I think one of those is necessarily better than the other and would probably just stick with casts.
精彩评论