C# 如何将泛型或对象参数转换为引用类型

C# 如何将泛型或对象参数转换为引用类型,c#,C#,在这个场景中,我不能为TypeA和TypeB创建一个要从中派生的基类型,因此我不能在方法上添加Where:TypeBase。我想看看是否有其他办法来解决这个问题 class TypeA { int number; string someString; } class TypeB { int number; decimal someDecimal; } private List<int> Test(object inputs) { List&

在这个场景中,我不能为TypeA和TypeB创建一个要从中派生的基类型,因此我不能在方法上添加Where:TypeBase。我想看看是否有其他办法来解决这个问题

class TypeA
{
    int number;
    string someString;
}

class TypeB
{
    int number;
    decimal someDecimal;
}

private List<int> Test(object inputs)
{
    List<int> rv = new List<int>();

    if (inputs is List<TypeA>)
        inputs = (List<TypeA>)inputs;
    else if(inputs is List<TypeB>)
        inputs = (List<TypeB>)inputs;

    foreach(item in inputs)
    {
        rv.Add(item.number);
    }
    return rv;
}
A类
{
整数;
字符串;字符串;
}
B类
{
整数;
十进制数;
}
私有列表测试(对象输入)
{
List rv=新列表();
if(输入为列表)
输入=(列表)输入;
else if(输入为列表)
输入=(列表)输入;
foreach(输入中的项目)
{
rv.添加(项目编号);
}
返回rv;
}

您可以将其强制转换为
IEnumerable
,然后执行
foreach
-循环:

private void Test(object inputs)
{
    // you can also change the parameter to IEnumerable to take advantage of compile-time type-checking.
    var items = inputs as IEnumerable;
    if (items == null)
        throw new ArgumentException("inputs");

    foreach (var item in items)
    {

    }
}
如果每个类的逻辑需要不同,请使用以下方法:

private void Test(object inputs)
{
    var typeAs = inputs as IEnumerable<TypeA>;
    if (typeAs != null)
    {
        foreach (var item in typeAs)
        {

        }
        return;
    }
    var typeBs = inputs as IEnumerable<TypeB>;
    if (typeBs != null)
    {
        foreach (var item in typeBs)
        {

        }
        return;
    }

    throw new ArgumentException("inputs");
}
私有无效测试(对象输入)
{
var typeAs=输入为IEnumerable;
if(typeAs!=null)
{
foreach(typeAs中的var项)
{
}
返回;
}
var typeBs=作为IEnumerable的输入;
if(typeBs!=null)
{
foreach(类型B中的var项目)
{
}
返回;
}
抛出新的ArgumentException(“输入”);
}

如果您独立地对它们进行迭代,则不会执行额外的工作:

class Program
{
    private void Test(object inputs)
    {
        if (inputs is List<TypeA>)
            loop((List<TypeA>) inputs);
        if (inputs is List<TypeB>)
            loop((List<TypeB>)inputs);
    }

    private void loop(IEnumerable<TypeA> inputs)
    {
        foreach (var input in inputs)
        {
            logic(input.i);
        }
    }

    private void loop(IEnumerable<TypeB> inputs)
    {
        foreach (var input in inputs)
        {
            logic(input.i);
        }
    }

    private void logic(int i)
    {
        // magic happens here
    }
}

class TypeA
{
    public int i;
}

class TypeB
{
    public int i;
}
类程序
{
专用无效测试(对象输入)
{
if(输入为列表)
循环((列表)输入);
if(输入为列表)
循环((列表)输入);
}
专用void循环(IEnumerable输入)
{
foreach(输入中的var输入)
{
逻辑(输入i);
}
}
专用void循环(IEnumerable输入)
{
foreach(输入中的var输入)
{
逻辑(输入i);
}
}
专用无效逻辑(int i)
{
//魔法在这里发生
}
}
A类
{
公共国际一级;
}
B类
{
公共国际一级;
}
但是为了世界上所有美好的事物,请不要这样做

如果出于某种原因,您确实必须一次遍历列表,并且您知道该测试将只使用TypeAs和TypeBs调用,那么您可以使用以下方法处理此问题:

类程序
{
静态void Main(字符串[]参数)
{
var w=新类型a{i=8};
var x=新类型a{i=16};
变量y=新类型b{i=32};
var z=new TypeC();//不要通过此测试!
var l=新列表{w,x,y};
试验(l);
}
专用静态无效测试(IEnumerable输入)
{
foreach(输入中的var输入)
{
逻辑(输入i);
}
}
专用静态无效逻辑(int i)
{
//魔法在这里发生
}
}
A类
{
公共国际一级;
}
B类
{
公共国际一级;
}
类TypeC{}//没有成员
私有void GenericTest(IEnumerable输入)
{
MethodInfo属性=typeof(T).GetProperty(/*您的属性*/).GetMethod;
foreach(输入中的var输入)
{
对象值=property.Invoke(输入,null);
//逻辑
}
}
//保护它不出错
公共无效测试(IEnumerable输入)
{
通用测试(输入);
}
//保护它不出错
公共无效测试(IEnumerable输入)
{
通用测试(输入);
}

顺便问一下,为什么不将属性名传递给测试方法?

您希望
项的类型是什么?你想对每个项目做什么?@JonSkeet项目可能是TypeA或TypeB,我只需要获取它们之间共享的公共值。我知道这可以通过使用带有where:BaseClass的基类或接口来实现,但我很好奇是否还有其他方法。对于每种类型,您在
foreach
循环中做了哪些不同的事情?@DStanley没有什么,逻辑相同,只是从公共属性中获取一个值可以使TypeA和TypeB实现共享接口(例如ICanDoLogic)?您为什么要避免单独迭代列表?也就是说,您希望通过首先合并列表获得什么?我不是说您不应该这样做,但我想了解您的用例。
class Program
{
    static void Main(string[] args)
    {
        var w = new TypeA {i = 8};
        var x = new TypeA {i = 16};
        var y = new TypeB {i = 32};
        var z = new TypeC(); // don't pass this to Test!
        var l = new List<dynamic> {w, x, y};
        Test(l);
    }

    private static void Test(IEnumerable<dynamic> inputs)
    {
        foreach (var input in inputs)
        {
            logic(input.i);
        }
    }

    private static void logic(int i)
    {
        // magic happens here
    }
}

class TypeA
{
    public int i;
}

class TypeB
{
    public int i;
}

class TypeC {} // no members 
private void GenericTest<T>(IEnumerable<T> inputs)
{
    MethodInfo property = typeof(T).GetProperty(/*YOUR PROPERTY*/).GetMethod;
    foreach (var input in inputs)
    {
        object value = property.Invoke(input, null);
        // Logic
    }
}

// To protect it from error
public void Test(IEnumerable<TypeA> inputs)
{
    GenericTest(inputs);
}

// To protect it from error
public void Test(IEnumerable<TypeB> inputs)
{
    GenericTest(inputs);
}