通过指定类型名称创建对象 [英] Create an object by specifying type name

查看:42
本文介绍了通过指定类型名称创建对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好:



我目前正在使用业务对象(来自 StrataFrame框架。我继承了BaseBusinessLayer(所有Business Objects的父类...为了便于参考,你可以把它想象成数据库中每个表的包装......这有相当于大多数类库。)我将这个基类修改为一个事件对象(稍后我会写和文章),这个类的基本功能之一是我可以使用另一个自定义将子BO添加到父业务对象class叫做childBOLoader ...这里是代码:

  namespace  SouthendBOL 
{
public class childBOLoader:Dictionary< string,BaseBusinessLayer>
{
public void Dispose()
{
dispose( true );
}

private void dispose( bool isDisposing)
{
if (isDisposing)
{
IEnumerator oEnum = GetEnumerator();
while (oEnum.MoveNext())
{
KeyValuePair< string,BaseBusinessLayer> pair =
((KeyValuePair< string,BaseBusinessLayer>)(oEnum.Current));
pair.Value.Dispose();
}
}
}

public void AddBO( string _name,BaseBusinessLayer _BO)
{
if ( !ContainsKey(_name))
{
Add(_name,_BO);
}
}

}
}



那是介绍...这是< b>问题:



在基础业务对象类中,我必须创建看起来像这样的代码...每个业务对象一个想要获得参考...以下是这些方法的两个例子:

  public  DialLog getDialLogBO( )
{
_childBOs.Add( oDialLog new DialLog());
return (DialLog)_childBOs [ oDialLog ];
}

public DialRecalls getDialRecallsBO()
{
_childBOs.Add( oDialRecalls new DialRecalls());
return (DialRecalls)_childBOs [ oDialRecalls ];
}







OO Design的一个主要租户是if如果我发现自己使用VB6继承方法(Ctrl + C紧跟一个Ctrl + V),我做错了。扩展这个逻辑,应该很清楚,如果我想将我的每个BO加载到我的事件对象中(事实并非如此,因为我需要加载的唯一BO是那些实际参与事件的人。但这可以说明我的观点)我必须为每个BO创建一个新方法。在我的例子中,这相当于添加到BaseBusinessLayer父类的29个方法,一个用于项目中的每个BO。现在这并没有以任何方式增加BaseBO的重量;但是,我想把它减少到一个 ......但我无法弄清楚如何做到这一点并保持类型安全。



PS ..以下是在事件处理中如何使用这些方法的示例:



  protected  覆盖  void  EventProcessing()
{
.EventProcessing();

PriceSectionFilter oPSF = getPriceSectionFilterBO();
PriceSections oPS = getPriceSectionsBO();
}





第二个问题:我是否在childBOLoader类中正确实现了IDisposable?



如果你花时间阅读这篇文章......谢谢!

解决方案

你可以做到,但这不是最好的主意,因为它对维护有害:如果名称被更改,您的代码将根据某个字符串值尝试创建具有旧名称的对象;并且编译器将无法检测到此问题。有些方法不依赖于任何魔法弦;例如,你可以找到一个实例 System.Type 实现某个接口并实例化它。



所以,让我们假设您已经找到了一些类型,一个 System.Type 的实例,比较一些程序集中的所有类型,并给出您的名字(如果您仍然需要这个名称)方式;如果你想用更好的方式,我的解决方案无论如何都会工作)。您可以找到所有类型和每个类型的全名(使用全名很重要),比如使用

http://msdn.microsoft.com/en-us/library/system.reflection.assembly.gettypes%28v=vs.110 %29.aspx [ ^ ],

http://msdn.microsoft.com/en-us/library/system.type.fullname%28v=vs.110%29.aspx [< a href =http://msdn.microsoft.com/en-us/library/system.type.fullname%28v=vs.110%29.aspxtarget =_ blanktitle =New Window> ^ ]。



现在,拥有 System.Type 的实例,你需要找到合适的构造函数。您甚至可以使用非公共构造函数。请参阅:

http:// msdn。 microsoft.com/en-us/library/h93ya84h(v=vs.110).aspx [ ^ ],

http://msdn.microsoft.com/en-us/library/0h6w8akb(v = vs.110)的.aspx [<一个href =http://msdn.microsoft.com/en-us/library/0h6w8akb(v=vs.110).aspx\"target =_ blanktitle =New Window> ^ ],

http://msdn.microsoft.com/ en-us / library / cs01xzbk(v = vs.110).aspx [ ^ ],

http://msdn.microsoft.com/en-us/library/e687hf0d(v=vs.110).aspx [ ^ ],

http://msdn.microsoft.com/en-us/library/h70wxday(ⅴ = vs.110).aspx [ ^ ]。



您可以通过签名(参数数量及其类型)选择要使用的构造函数绑定标志(你需要实例构造,实例化任何东西,公共与否)。



这一步将为你提供系统的实例.Reflection.ConstructorInfo

http://msdn.microsoft.com/en-us/library/system.reflection.constructorinfo%28v=vs.110%29.aspx [ ^ ]。



作为最后一步,你需要调用您选择的构造函数,可选择向其传递适当数量的参数:

http://msdn.microsoft.com/en-us/library/6ycw1y17(v = vs.110).aspx [ ^ ],

http://msdn.microsoft.com/en-us/library/a89hcwhh(v=vs .110).aspx [ ^ ],

http://msdn.microsoft.com/en-us/library/x7xy3xtx(v = vs.110).aspx [ ^ ],

http://msdn.microsoft.com/en-us/library/4k9x6bc0(v = vs.110).aspx [ ^ ]。



这个 ConstructorInfo.Invoke 调用将始终返回 System.Object 的实例,您需要将其输入到期望的类型。



这就是全部。请享用。 :-)



-SA


关于你的第二个问题:见MSDN:实现完成和处理以清理非托管资源 [ ^ ]。



我对你的代码有几点评论:



  • C#的异常命名方案(不一致的低/大写措辞等)。请参阅开发类库的设计指南 [ ^ ]。
  • 你使用派生,其中组成可能更清晰:为什么 childBOLoader 派生自 Dictionary ?是否要将所有Dictionary方法公开给 childBOLoader 类的客户端?没人会指望 childBOLoader Dictionary 。更好地使用组合。
  • 您的类没有实现IDisposable接口(它在类头中缺失)。为什么你认为你需要处置任何东西 - 你在垃圾收集环境中。
  • 你无缘无故地使用演员阵容 - 我认为演员阵容是代码气味,即避免或评论为什么无法避免。请改用通用枚举器。但是由于你的Is-A字典而不是Has-A字典实现,无论如何你看起来如何枚举字典的内容看起来很奇怪。如果它是cmposition,你会做一个foreach循环(你也可以在这里做:

      foreach  var  item  in  values)
    {
    var obj = item as IDisposable; // 仅调用Dispose on IDisposable对象
    如果(obj!= null )obj.Dispose() ;
    }

    或更简单如果你 BaseBusinessLayer 类实现 IDisposable

      foreach  var  item  in 值)item.Dispose(); 



干杯

Andi


关于创建各种业务对象(没有看到更多的架构)我会考虑一个构造函数/ getter函数,它将构造表达式作为lambda并创建并将对象插入 _childBOs 字典

< pre lang =c#> public BaseBusinessLayer getBO(Func< BaseBusinessLayer>工厂)
{
BaseBusinessLayer newBO = factory();
string boName = newBO.GetType()。Name;
_childBOs.Add(boName);
返回 newBO;
}



然后你会调用它:

 BaseBusinessLayer someBO = getBO(()= >   new  DialRecalls()); 





如果您不喜欢lambda表达式的想法,那么您可以使用泛型重构继承层次结构,因此允许 static 方法,在 BaseBusinessLayer 类中实现一次来生成实例。

 < span class =code-keyword>使用系统; 

命名空间 ConsoleApplication27
{
class Program
{
静态 void Main( string [] args)
{
var dl = DialLog.Factory();
Console.WriteLine( dl是类型: + dl.GetType()。名称);
var dr = DialRecalls.Factory();
Console.WriteLine( dr类型: + dr.GetType()。名称);
}
abstract class BaseBusinessLayer< T> 其中 T:BaseBusinessLayer< T>, new ()
{
protected BaseBusinessLayer()
{
}
static public T Factory()
{
return new T();
}
}
class DialLog:BaseBusinessLayer< DialLog>
{
}
class DialRecalls:BaseBusinessLayer< DialRecalls>
{
}
}
}



使用 getBO 上面的方法是:

 BaseBusinessLayer someBO = getBO(DialRecalls.Factory); 


Hello everyone:

I'm currently working with a Business Object (from the StrataFrame Framework. I have inherited from the BaseBusinessLayer (parent class for all Business Objects ... for ease of reference you can think of this as a wrapper around each table in the database ... there are equivalents to this in most class libraries). I modified this base class to be an event object (I'll write and article about that later) and one of the base functionalities of this class is that I can add child BO's to the parent business object using another custom class called a childBOLoader ... here is the code for that:

namespace SouthendBOL
{
    public class childBOLoader : Dictionary<string, BaseBusinessLayer>
    {
        public void Dispose()
        {
            dispose(true);
        }

        private void dispose(bool isDisposing)
        {
            if (isDisposing)
            {
                IEnumerator oEnum = GetEnumerator();
                while (oEnum.MoveNext())
                {
                    KeyValuePair<string, BaseBusinessLayer> pair =
                               ((KeyValuePair<string, BaseBusinessLayer>)(oEnum.Current));
                    pair.Value.Dispose();
                }
            }
        }

        public void AddBO(string _name, BaseBusinessLayer _BO)
        {
            if (!ContainsKey(_name))
            {
                Add(_name, _BO);
            }
        }

    }
}


That was the introduction ... this is the Problem:

On the base business object class I have to create code that looks like this ... one for each business object to which I want to obtain a reference ... here are two examples of those methods:

public DialLog getDialLogBO()
{
    _childBOs.Add("oDialLog", new DialLog());
    return (DialLog)_childBOs["oDialLog"];
}

public DialRecalls getDialRecallsBO()
{
    _childBOs.Add("oDialRecalls", new DialRecalls());
    return (DialRecalls)_childBOs["oDialRecalls"];
}




One of my key tenants of OO Design is if that if I find myself using the VB6 method of inheritance (Ctrl+C followed closely by a Ctrl+V) that I'm doing something wrong. Extending this logic, it should become clear that if I wanted to load each and every one of my BOs into my event object (this is not really the case since the only BOs I need to load are those few who actually participate in events ... but this serves to illustrate my point) I would have to create a new method for each BO. In my case this equates to 29 methods added to the BaseBusinessLayer parent class, one for each BO in the project. Now this does not add to the "weight" of the BaseBO in any way; however, I want to reduce this to ONE ... but I cannot figure out how to do that and maintain type safety.

PS .. here is an example of how these methods are used in Event Processing:

 protected override void EventProcessing()
 {
    base.EventProcessing();
       
    PriceSectionFilter oPSF = getPriceSectionFilterBO();
    PriceSections oPS = getPriceSectionsBO();
}



Second Question: Am I implementing IDisposable correctly in the childBOLoader class?

If you took the time to read this far ... THANKS!

解决方案

You can do it, but this is not the best idea, because it is bad for maintenance: if a name is changed, your code depending on some string value will try to create an object with an old name; and the compiler won't be able to detect this problem. There are approaches not depending on any "magical strings"; for example, you can find an instance of System.Type implementing certain interface and instantiate it.

So, let's assume that you already found some type, an instance of System.Type by comparing, say, all types in some assembly, with you given name (if you still need this bad way; if you want to use better way, my solution will work anyway). You could find all types and the full name (it's important to use full name) of each, say, using
http://msdn.microsoft.com/en-us/library/system.reflection.assembly.gettypes%28v=vs.110%29.aspx[^],
http://msdn.microsoft.com/en-us/library/system.type.fullname%28v=vs.110%29.aspx[^].

Now, having the instance of System.Type, you need to find appropriate constructor. You can even use a non-public constructor. Please see:
http://msdn.microsoft.com/en-us/library/h93ya84h(v=vs.110).aspx[^],
http://msdn.microsoft.com/en-us/library/0h6w8akb(v=vs.110).aspx[^],
http://msdn.microsoft.com/en-us/library/cs01xzbk(v=vs.110).aspx[^],
http://msdn.microsoft.com/en-us/library/e687hf0d(v=vs.110).aspx[^],
http://msdn.microsoft.com/en-us/library/h70wxday(v=vs.110).aspx[^].

You can choose the constructor you want to use by its signature (number of parameters and their types) and binding flags (you will need instance constuctor, to instantiate anything, public or not).

This step will give you the instance of the System.Reflection.ConstructorInfo:
http://msdn.microsoft.com/en-us/library/system.reflection.constructorinfo%28v=vs.110%29.aspx[^].

As the final step, you need to invoke the constructor of your choice, optionally passing appropriate number of parameters to it:
http://msdn.microsoft.com/en-us/library/6ycw1y17(v=vs.110).aspx[^],
http://msdn.microsoft.com/en-us/library/a89hcwhh(v=vs.110).aspx[^],
http://msdn.microsoft.com/en-us/library/x7xy3xtx(v=vs.110).aspx[^],
http://msdn.microsoft.com/en-us/library/4k9x6bc0(v=vs.110).aspx[^].

This ConstructorInfo.Invoke call will always return you the instance of System.Object which you will need to type-cast to the expected type.

That's all. Enjoy. :-)

—SA


To your second question: See MSDN: Implementing Finalize and Dispose to Clean Up Unmanaged Resources[^].

I have several comments on your code:

  • unusual naming scheme for C# (inconsitent lower/upper case wording, etc.). Have a look at Design Guidelines for Developing Class Libraries[^].
  • you use derivation where composition is probably clearer: why childBOLoader to derive from Dictionary? Do you want expose all Dictionary methods to the client of the childBOLoader class? No one would expect the childBOLoader to be a Dictionary. Better use composition instead.
  • Your class does not implement IDisposable interface (it's missing in the class header). Why do you think you need to dispose anything - you are here in a garbage collected environment.
  • You are using casts without cause - I regard casts as code smell, i.e. either avoid or comment why cannot avoid. Use the generic enumerator instead. But since your "Is-A" Dictionary instead of a "Has-A" Dictionary implementation, it looks odd anyways how you enumerate over the content of the dictionary. If it was cmposition, you would do a foreach loop (you can do that here too:

    foreach (var item in Values)
    {
       var obj = item as IDisposable; // only call Dispose on IDisposable objects
       if (obj != null) obj.Dispose(); 
    }

    or simpler if you BaseBusinessLayer class implements IDisposable:

    foreach (var item in Values) item.Dispose();


Cheers
Andi


Regarding creation of the various business objects (without seeing more of your architecture) I'd consider a single builder/getter function that takes the construction expression as a lambda and creates and inserts the object into the _childBOs Dictionary

public BaseBusinessLayer getBO(Func<BaseBusinessLayer> factory)
{
    BaseBusinessLayer newBO = factory();
    string boName = newBO.GetType().Name;
    _childBOs.Add(boName);
    return newBO;
}


And then you would invoke it like:

BaseBusinessLayer someBO = getBO(() => new DialRecalls());


[Edit]
If you don't like the idea of the lambda expressions, then you can restructure the inheritence hierarchy using generics so allow for a static method, implemented once in the BaseBusinessLayer class to factory the instances.

using System;

namespace ConsoleApplication27
{
  class Program
  {
    static void Main(string[] args)
    {
      var dl = DialLog.Factory();
      Console.WriteLine("dl is type: " + dl.GetType().Name);
      var dr = DialRecalls.Factory();
      Console.WriteLine("dr is type: " + dr.GetType().Name);
    }
    abstract class BaseBusinessLayer<T> where T:BaseBusinessLayer<T>, new()
    {
      protected BaseBusinessLayer()
      {
      }
      static public T Factory()
      {
        return new T();
      }
    }
    class DialLog : BaseBusinessLayer<DialLog>
    {
    }
    class DialRecalls : BaseBusinessLayer<DialRecalls>
    {
    }
  }
}


And the use with the getBO method above would be:

BaseBusinessLayer someBO = getBO(DialRecalls.Factory);


这篇关于通过指定类型名称创建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆