多个类的C#泛型方法

时间:2014-10-29 23:10:43

标签: c# .net linq generics reflection

我试图寻找解决方案,但我的问题是我甚至不知道使用什么术语。泛型,代表,Linq,反思,抽象的想法可能是解决方案的一部分,但我的“googlephu”没有出现在右边。

问题: 我有多个类(ClassA,ClassB,Class C)都具有相同的2-3个属性DoThisA,DoThisB,DoThisC

代码的工作方式是我总是希望在处理每个类时使用相同的代码来设置DoThisA,DoThisB和DoThisC。

例如,为了简化,逻辑将永远是:

{some computations to set string currentValueImProcessing to something}
if (xyz) [ClassA|B|C].DoThisA = currentValueImProcessing
else [ClassA|B|C].DoThisB = currentValueImProcessing

我不想一遍又一遍地编写那些相同的语句,所以我如何只将类(A,B,C)的引用发送到一个方法来做逻辑

如果写得正确,ClassA,ClassB和ClassC中的每一个都会实现一些泛型类,我可以使用它,但我不能。每个类都是独立的,但具有相同的命名属性。

关于概念/代码的任何指导?

谢谢!

5 个答案:

答案 0 :(得分:4)

为您的媒体资源创建interface

internal interface IDoThis
{
    public string DoThisA { get; set; }
    public string DoThisB { get; set; }
    public string DoThisC { get; set; }
}

然后,让你的类实现它:

public class ClassA : IDoThis
{
    public string DoThisA { get; set; }
    public string DoThisB { get; set; }
    public string DoThisC { get; set; }
}

public class ClassB : IDoThis
{
    // Same properties
}

public class ClassC : IDoThis
{
    // Same properties
}

这样,您就可以在某处创建静态初始化方法:

internal static class MyClassesExtensions
{
    public static void InitTheStuff(this IDoThis obj)
    {
        // Do something here, for example:
        if (String.IsNullOrEmpty(obj.DoThisA))
            obj.DoThisA = "foo";
        else
            obj.DoThisB = obj.DoThisC;
    }
}

然后,您可以在this.InitTheStuff()ClassAClassB的任何地方拨打ClassC

答案 1 :(得分:3)

你可以使用反射,也可以使用动态(动态会为你使用反射)

dynamic obj = new ClassA();
obj.DoTHisA();

是如何使用动态

来完成的

我假设您正在谈论您打算实例化的类。如果DoThisA,B,C是静态方法,则必须使用反射

注意 - 如果您可以更改类,则按其他人的建议添加接口,或者甚至是公共基类

反射看起来像这样

var type = obj.GetType(); // obj is ClassX object
var method = type.GetMethod("DoTHisA");
method.Invoke(obj);

我没有检查过 - 所以语法可能有点偏离 - 但这是反射方法调用的基本机制。如果有多个具有相同名称的方法,如果方法采用params等,你需要变得更加漂亮

答案 2 :(得分:1)

问你正在谈论继承。

对于您的任务,您需要一个具有常规属性的基本抽象类:

public abstract class Base
{
    public bool DoThisA { get; set; }

    public bool DoThisB { get; set; }
}

和子课程:

public class A : Base { }
public class B : Base { }
public class C : Base { }

之后,您可以创建一个接受Base

类型对象的方法
public void Do(Base b, bool xyz, bool currentValueImProcessing)
{
    if (xyz)
    {
        b.DoThisA  = currentValueImProcessing;
    }
    else
    {
        b.DoThisB  = currentValueImProcessing;
    }
}

答案 3 :(得分:1)

至少有四种选择 - 或许更多。

  1. 创建一个界面,该界面由所有类实现,包括常用方法。
  2. 创建一个所有类继承的基类。然后可以在基类中实现通用功能。如果实现因clases而异,但您可以为方法定义常用签名,请使您的基类成为常见的功能抽象。然后,您可以在每个类中实现实际功能。
  3. 在@ pm100的解决方案中使用动态对象。
  4. 使用反射来访问常用功能。
  5. 作为指导方法1.和2.是首选,因为它们允许在编译时检查代码。但是,如果您无法控制包含常用功能的类 - 例如,您无权访问源代码或者您可以更改代码 - 则可以使用其他两种方法。

    如果你问我想要哪两个,我想我会选择3.超过4.但这是个人偏好。

答案 4 :(得分:0)

这里已经提供了很多方法,所以只是为了完整性......这里有一些运行时代码生成:

public class ClassA
{
    public string DoThisA { get; set; }
    public int DoThisB { get; set; }
    public bool DoThisC { get; set; }

    public void Init()
    {
        // You can call this from anywhere, even from an unrelated class
        MyClassInitializer<ClassA>.Init(this);
    }
}

public static class MyClassInitializer<T>
{
    // Create the getters/setters you need, and make sure they're static.

    private static readonly Func<T, string> _getA = BuildGetter<string>("DoThisA");
    private static readonly Action<T, string> _setA = BuildSetter<string>("DoThisA");

    private static readonly Func<T, int> _getB = BuildGetter<int>("DoThisB");
    private static readonly Action<T, int> _setB = BuildSetter<int>("DoThisB");

    private static readonly Func<T, bool> _getC = BuildGetter<bool>("DoThisC");
    private static readonly Action<T, bool> _setC = BuildSetter<bool>("DoThisC");

    private static Func<T, TValue> BuildGetter<TValue>(string name)
    {
        var obj = Expression.Parameter(typeof(T));
        return Expression.Lambda<Func<T, TValue>>(Expression.Property(obj, name), obj).Compile();
    }

    private static Action<T, TValue> BuildSetter<TValue>(string name)
    {
        var obj = Expression.Parameter(typeof(T));
        var value = Expression.Parameter(typeof(TValue));
        return Expression.Lambda<Action<T, TValue>>(Expression.Assign(Expression.Property(obj, name), value), obj, value).Compile();
    }

    public static void Init(T obj)
    {
        // Here's your custom initialization method

        if (_getA(obj) == "Foo")
            _setB(obj, 42);
        else
            _setC(obj, true);
    }
}

不一定是最容易掌握的,但这应该比使用dynamic或反射要快得多。也就是说,如果你不需要速度,请坚持dynamic,因为它更容易。