【问题标题】:Generic interface inheritance castings通用接口继承强制转换
【发布时间】:2017-10-24 11:03:54
【问题描述】:

目前,我面临一个通用接口继承问题:

interface IParent<T> {
    R Accept<R>(IParentVisitor<T, R> visitor);
}

interface IChild<T, TKey> : IParent<T> {
   R Accept<R>(IChildVisitor<T, TKey, R> visitor);
}

我还创建了这些Visitor 接口:

interface IParentVisitor<T, R> {
    R Visit(IParent<T> parent);
}

interface IChildVisitor<T, TKey, R> : IParentVisitor<T, R> {
    R Visit(IChild<T, TKey> viz);
}

实现:

class ParentVisitor<T> : IParentVisitor<T, MyResultClass> {
    MyResultClass Visit(IParent<T> parent) {
      return //...;
    }
}

class ChildVisitor<T, TKey> : IChildVisitor<T, TKey, MyAnotherResultClass> {
    MyAnotherResultClass Visit(IChild<T, TKey> child) {
      return //...;
    }
}

到目前为止,一切似乎都是正确的。不过,猜猜这种情况:

static void Main() {
    IList<IParent<MyT>> interfaces = new List<IParent<MyT>>();
    interfaces.add(new Parent<MyT>());
    interfaces.add(new Child<MyT, string>());
    interfaces.add(new Child<MyT, int>());
    interfaces.add(new Child<MyT, TimeSpan>());
    //...

    //(!!*!!)
    foreach (IChild<MyT, string> stringChild in interfaces.OfType<IChild<MyT, string>()) {
      ChildVisitor stringChildVisitor = new ChildVisitor<MyT, string>();
      var result = stringChild.Accept(stringChildVisitor);
      //...
    }

    //(!!*!!)
    foreach (IChild<MyT, int> intChild in interfaces.OfType<IChild<MyT, int>()) {
      ChildVisitor intChildVisitor = new ChildVisitor<MyT, int>();
      var result = stringChild.Accept(intChildVisitor);
      //...
    }

    //and so on up to infitiny types in C#...
}

我认为这是获得我想要的东西的一种不可行的方式。

我想要得到的是在IChild&lt;T, *&gt; 上使用ChildVisitor,其中* 是任何类型。不知道我解释的好不好。

类似的东西:

//(!!*!!)
foreach (IChild<MyT, *> asterisckChild in interfaces.OfType<IChild<MyT, *>()) {
  ChildVisitor asterisckChildVisitor = new ChildVisitor<MyT, *>();
  var result = asterisckChild.Accept(asterisckChildVisitor);
  //...
}

有什么想法吗?

【问题讨论】:

  • ChildVisitor 中接受孩子时,您真的关心TKey 是什么吗?
  • 我想你的意思是,如果TKey 用于ChildVisitor.Visit 实现?是的。
  • 反思可以提供帮助,但你真的想走这条路吗? foreach(var it in interfaces) foreach(var face in it.GetType().GetInterfaces()) if(typeof(IChild&lt;,&gt;).IsAssignableFrom.... ..不确定最后一个,但写起来会很恐怖
  • 我认为我使用了一种非最佳实践的方法来设计这种行为......但是,我不太清楚如何得到它......
  • @firda 你能给我一个答案,提供一些关于你的方法的额外帮助代码吗?

标签: c# .net generics design-patterns visitor-pattern


【解决方案1】:
IList list = new ArrayList();
list.Add(new Dictionary<string, string>
{
    ["key"] = "value"
});
list.Add(new Dictionary<string, int>()
{
    ["key"] = 123
});
list.Add("just for the test");

foreach(var it in list)
{
    foreach(var face in it.GetType().GetInterfaces())
    {
        //1. Filter out non-generic interfaces
        // (following GetGenericTypeDefinition() would throw exception otherwise)
        if (!face.IsGenericType)
            continue;

        //2. Filter out anything that is not IDictionary<,>
        if (typeof(IDictionary<,>) != face.GetGenericTypeDefinition())
            continue;

        //3. Filter out anything that is not IDictionary<string,>
        var generic = face.GetGenericArguments();
        if (typeof(string) != generic[0]) //note: consider IsAssignableFrom instead
            continue;

        //4. Invoke the method
        var valueType = generic[1];
        var method = face.GetMethod("TryGetValue"); //note: needs to be more specific if overloaded

        //don't know how you want to choose R for the Accept<R>
        //method = method.MakeGenericMethod(new[] { typeof(R) });

        var arguments = new object[] { "key", null };
        method.Invoke(it, arguments);
        var value = arguments[1];

        //5. Do something with the result
        Console.WriteLine(value.ToString());
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-05
    • 2012-09-04
    • 1970-01-01
    • 2012-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多