C# 将泛型类型强制转换为子类

C# 将泛型类型强制转换为子类,c#,generics,C#,Generics,我从泛型类型开始,我一直坚持我的项目。也许我不太懂泛型。解释已插入内联。基本上我需要实现Do()方法,但我不知道如何解决: 公共抽象类MyGenericClass{} 公共类MyGenericClass:MyGenericClass { 公开表达; 公共MyGenericClass(表达式) { 这个表达式=表达式; } } 公共类MyClass { //我需要保存一个泛型类的列表,以便以后使用。 //我现在不知道T2。 //所以我选择使用继承作为解决方法(MyGenericClass和MyGe

我从泛型类型开始,我一直坚持我的项目。也许我不太懂泛型。解释已插入内联。基本上我需要实现
Do()
方法,但我不知道如何解决

公共抽象类MyGenericClass{}
公共类MyGenericClass:MyGenericClass
{
公开表达;
公共MyGenericClass(表达式)
{
这个表达式=表达式;
}
}
公共类MyClass
{
//我需要保存一个泛型类的列表,以便以后使用。
//我现在不知道T2。
//所以我选择使用继承作为解决方法(MyGenericClass和MyGenericClass)。
//也许这不是个好办法,但我找不到其他办法。
公共列表MyGenericList=新列表();
//我在这里接收参数参数T2作为表达式的一部分。
//我在列表中保留了这个表达式。
公共MyGenericClass接收方法(表达式)
{
MyGenericClass GenericMP=新的MyGenericClass(表达式);
添加(genericmp);
返回genericmp;
}
}
公共类客户端
{
我的班级1;
//class1已创建,其字段MyGenericList已填充。
//然后当我调用Do()。。。。
公营部门
{
foreach(class1.MyGenericList中的变量项)
{
//我需要这样的东西,
//但它没有编译,因为我不知道这里的T2。
//Do()方法的调用方不知道T2。
MyGenericClass myGenericItem=(MyGenericClass)项;
var a=myGenericItem.expression;
}
}
}
您必须以某种方式为
Do()
提供
T2
参数。因此,我的解决方案是创建一个相同类型的方法参数。我还嵌套了这些类型,以确保它们都引用相同的
T

我还将参数重命名为更具描述性的参数

//  T  -> TArg
//  T2 -> TResult
public abstract class MyBaseClass<TArg>
{
    public class MyExpressionClass<TResult> : MyBaseClass<TArg>
    {
        public Expression<Func<TArg, TResult>> Expression { get; private set; }
        public MyExpressionClass(Expression<Func<TArg, TResult>> expression)
        {
            this.Expression=expression;
        }
    }

    public class MyCollectionClass 
    {
        public List<MyBaseClass<TArg>> MyGenericList = new List<MyBaseClass<TArg>>();

        public MyExpressionClass<TResult> ReceivingMethod<TResult>(Expression<Func<TArg, TResult>> expression)
        {
            var genericImp = new MyExpressionClass<TResult>(expression);
            MyGenericList.Add(genericImp);
            return genericImp;
        }
    }

    public class Client
    {
        public MyCollectionClass List = new MyCollectionClass();

        public void Do<TResult>()
        {
            foreach(var item in List.MyGenericList)
            {
                var expr = item as MyExpressionClass<TResult>;
                if(expr!=null)
                {
                    var a = expr.Expression;
                    Console.WriteLine(a);
                }
            }
        }
    }
}



class Program
{
    static void Main(string[] args)
    {
        var client = new MyBaseClass<int>.Client();
        // add conversion expressions
        client.List.ReceivingMethod((i) => (i).ToString());
        client.List.ReceivingMethod((i) => (2*i).ToString());
        client.List.ReceivingMethod((i) => (3*i).ToString());

        // The programmer has to manually enforce the `string` type
        // below based on the results of the expressions above. There
        // is no way to enforce consistency because `TResult` can be 
        // _any_ type. 
        client.Do<string>();

        // Produces the following output
        //
        // i => i.ToString()
        // i => (2*i).ToString()
        // i => (3*i).ToString()
    }
}
//T->target
//T2->TResult
公共抽象类MyBaseClass
{
公共类MyExpressionClass:MyBaseClass
{
公共表达式{get;private set;}
公共MyExpressionClass(表达式)
{
这个表达式=表达式;
}
}
公共类MyCollectionClass
{
公共列表MyGenericList=新列表();
公共MyExpressionClass接收方法(表达式)
{
var genericmp=新的MyExpressionClass(表达式);
添加(genericmp);
返回genericmp;
}
}
公共类客户端
{
public MyCollectionClass List=new MyCollectionClass();
公营部门
{
foreach(List.MyGenericList中的变量项)
{
var expr=作为MyExpressionClass的项;
如果(expr!=null)
{
变量a=表达式;
控制台写入线(a);
}
}
}
}
}
班级计划
{
静态void Main(字符串[]参数)
{
var client=new MyBaseClass.client();
//添加转换表达式
client.List.ReceivingMethod((i)=>(i.ToString());
client.List.ReceivingMethod((i)=>(2*i.ToString());
client.List.ReceivingMethod((i)=>(3*i.ToString());
//程序员必须手动执行'string'类型
//下面是基于上述表达式的结果
//无法强制执行一致性,因为'TResult'可以
//任何类型。
client.Do();
//生成以下输出
//
//i=>i.ToString()
//i=>(2*i).ToString()
//i=>(3*i).ToString()
}
}

解决方案1灵感来源于@KMoussa comment。我已使用抽象方法将责任委托给
MyGenericClass
。这似乎是一个更好的设计。所有子类都将实现此方法
DoTheWork()
。只能使用
T
param从我的
Client.Do()
方法调用:

public abstract class MyGenericClass<T>
{
    public abstract string DoTheWork();
}

public class MyGenericClass<T, T2> : MyGenericClass<T>
{
    public override string DoTheWork()
    {
        // I can use expression here
    }

    private Expression<Func<T, T2>> expression { get; set; }

    public MyGenericClass(Expression<Func<T, T2>> expression)
    {
        this.expression = expression;
    }
}

public class MyClass<T>
{
    public List<MyGenericClass<T>> MyGenericList = new List<MyGenericClass<T>>();
    public void ReceivingMethod<T2>(Expression<Func<T, T2>> expression)
    {
        MyGenericClass<T, T2> genericImp = new MyGenericClass<T, T2>(expression);
    }
}

public class Client<T>
{
    MyClass<T> class1;
    public void Do()
    {
        // I don't need to cast to MyGenericClass<T, T2>
        foreach (MyGenericClass<T> myGenericItem in class1.MyGenericList)
        {
                string result = myGenericItem.DoTheWork();
        }
    }
}

你考虑过使用而不是吗?此时你必须使用反射。或者真的试着想出一个不同的设计。泛型意味着允许您编写基本上独立于类型的代码,而不允许您将许多不同类型分组在一起。如何使用
Do
myGenericItem?如果它不需要执行任何特定于
T2
的操作,那么您可以在
MyGenericClass
上定义抽象方法,该方法在派生类中实现,并由
do
@Jesus调用。我的意思是,您为什么需要访问表达式?只是为了执行它并得到Func的结果吗?因为如果是这样的话,你可以有一个为t2返回对象的抽象方法,我看到两个危险信号。a) 构建层次结构以处理各种
表达式
,而不是直接保留
Func
;b)创建基类型列表并尝试强制转换为派生类型。不幸的是,
C#
在这方面相当薄弱。另外,我建议嵌套所有需要
的类型,以减少声明量。我无法编译
MyExpressionClass…
。我需要添加类型参数
TArg
MyExpressionClass…
进行编译。问题是
Do()
的调用方不知道
我的示例中的代码编译率为100%。我在发帖前检查过了。如果你有错误,可能是某个地方的打字错误
MyExpression
嵌套在
MyBaseClass
中,并从中使用
TArg
。是的,编译率为100%。我看不出类是嵌套的。很抱歉
public abstract class MyGenericClass<T>
{
    public abstract string DoTheWork();
}

public class MyGenericClass<T, T2> : MyGenericClass<T>
{
    public override string DoTheWork()
    {
        // I can use expression here
    }

    private Expression<Func<T, T2>> expression { get; set; }

    public MyGenericClass(Expression<Func<T, T2>> expression)
    {
        this.expression = expression;
    }
}

public class MyClass<T>
{
    public List<MyGenericClass<T>> MyGenericList = new List<MyGenericClass<T>>();
    public void ReceivingMethod<T2>(Expression<Func<T, T2>> expression)
    {
        MyGenericClass<T, T2> genericImp = new MyGenericClass<T, T2>(expression);
    }
}

public class Client<T>
{
    MyClass<T> class1;
    public void Do()
    {
        // I don't need to cast to MyGenericClass<T, T2>
        foreach (MyGenericClass<T> myGenericItem in class1.MyGenericList)
        {
                string result = myGenericItem.DoTheWork();
        }
    }
}
public abstract class MyGenericClass<T>
{
    public abstract Type type { get; set; }
}

public class MyGenericClass<T, T2> : MyGenericClass<T>
{
    public Expression<Func<T, T2>> expression { get; set; }

    public MyGenericClass(Expression<Func<T, T2>> expression)
    {
        type = typeof(T2);  // I save the type of T2
        this.expression = expression;
    }
}

public class MyClass<T>
{
    public List<MyGenericClass<T>> MyGenericList = new List<MyGenericClass<T>>();
    public void ReceivingMethod<T2>(Expression<Func<T, T2>> expression)
    {
        MyGenericClass<T, T2> genericImp = new MyGenericClass<T, T2>(expression);
    }
}

public class Client<T>
{
    MyClass<T> class1;
    public void Do()
    {
        foreach (MyGenericClass<T> myGenericItem in class1.MyGenericList)
        {
            MethodInfo method = GetType().GetMethod("MethodWithArgument");
            MethodInfo generic = method.MakeGenericMethod(new Type[] { myGenericItem.type });
            string g = (string)generic.Invoke(this, new object[] { myGenericItem });
        }
    }

    // I introduce T2 in this method
    public string MethodWithArgument<T2>(MyGenericClass<T> myClass)
    {
        // Now, the casting is valid
        MyGenericClass<T, T2> mySubClass = (MyGenericClass<T, T2>)myClass;
        var a = mySubClass.expression;
        // I can work with expression here
    }
}