首页 \ 问答 \ 基类方法是否可以返回派生类的类型?(Can a Base Class Method return the type of the derived class?)

基类方法是否可以返回派生类的类型?(Can a Base Class Method return the type of the derived class?)

根据我读过的其他帖子,似乎这可能是不可能的,但我想我会发布我正在尝试做的事情,看看有没有人知道解决方案。

我正在尝试为从Telerik Open Access域模型生成的类添加“Clone()”方法。 没问题。 我能够弄清楚如何将基类添加到生成的实体模型,以便我可以通过它们的基类识别这些类。 ( 所有实体都从基类继承

我希望所有这些实体模型类都能克隆自己。 我也找到了解决方案。 ( 深层克隆对象

现在我有一个基类,我想为每个从该基类派生的类添加一个Clone()函数。 所以......看起来基类是放它的自然地方......对吗?

public abstract class DBEntityBase
{
    /// <summary>
    ///     Gets a COPY of the instance in it's current state
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected T Clone<T>()
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this));
    }
}

我添加受保护的通用Clone()方法,因为在基类级别上我们不知道我们正在克隆的Type。 Clone()方法需要由实体模型本身来实现,以提供被克隆的特定类型。

public partial class DeliverableEntity
{
    public new DeliverableEntity Clone()
    {
        return this.Clone<DeliverableEntity>();
    }
}

这可以正常工作,但不能保证派生类将公开地公开一个Clone()方法,所以我向该基类添加了一个抽象Clone()方法,这将需要派生类实现公共Clone()方法。

public abstract class DarkRoomDBEntityBase
{
    /// <summary>
    ///     Gets a COPY of the instance in it's current state
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected T Clone<T>()
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this));
    }

    /// <summary>
    ///     Gets a deep COPY of the entity instance
    /// </summary>
    /// <returns></returns>
    public abstract DBEntityBase Clone();
}

我给它一个基类本身的返回类型; 每个实现必须返回一个遵循DBEntityBase的值,当然,所有派生类都会这样做。 由于Clone()方法正在返回派生类本身的类型,所以...似乎有意义的是,这会起作用。

DeliverableEntity originalEntity = new DeliverableEntity();
DeliverableEntity clonedEntity   = originalEntity.Clone();

然而,在建设时,我得到了错误。

'DeliverableEntity'没有实现继承的抽象成员'DBEntityBase.Clone()'

可能是由于返回类型。

我知道我可以把Clone()方法放在一个单独的工具类中,而不是直接在每个实体模型中实现它......这会让我绕过我的问题(并且可能会节省大量的实现代码),但是我仍然想知道为什么这不起作用。 似乎应该有办法做到这一点。

UPDATE

为了回应@ Luann的第一个回复(谢谢),我改变了“重写”......

public partial class DeliverableEntity
{
    public override DeliverableEntity Clone()
    {
        return this.Clone<DeliverableEntity>();
    }
}

并且现在收到以下错误...

返回类型必须是'DBEntityBase'以匹配重写的成员'DBEntityBase.Clone()'

感谢Flynn1179,我能够再次前进。 我想我会花一点时间来记录我在这里做了什么以备将来参考。

我没有为ORM中的每个实体模型创建一个部分类,而是实现了一个抽象方法,而是按照建议创建了一个扩展方法。

namespace DAL
{
    public partial class DeliverableEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }

    public partial class DeliverableItemEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }

    public partial class DeliverableItemAttrEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }
}

namespace DAL
{
    public static class EntityExtensionMethods
    {
        public static T Clone<T>(this T entity) where T: DBEntityBase
        {
            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(entity));
        }
    }
}

有些事情要注意...

  • 将这个类放置在与实体模型相同的名称空间中。 如果它位于不同的名称空间中,则需要添加该名称空间才能访问该方法。
  • 我将泛型类型的约束定义为仅继承DBEntityBase类的所有类。 由于我让所有的实体模型类都从这个基类派生出来,我知道它们都会公开这个方法,但是任何不从这个类派生的类都不具备这个能力。
  • 扩展方法和包含它的类必须是静态的

现在最酷的部分是所有的实体都可以访问该功能......

    // Create the original instances of the entities    
    DeliverableEntity origDeliverable       = new DeliverableEntity();
    DeliverableItemEntity origItem          = new DeliverableItemEntity();
    DeliverableItemAttrEntity origItemAttr  = new DeliverableItemAttrEntity();

    // now here's the magic 

    DeliverableEntity cloneDeliverable      = origDeliverable.Clone();
    DeliverableItemEntity cloneItem         = origItem.Clone();
    DeliverableItemAttrEntity cloneItemAttr = origItemAttr.Clone();

我喜欢这个解决方案,因为它具有基类的简单性,其中实现在单个位置定义(而我正在寻找在每个派生类中分别实现抽象方法),另外还因为它与DBEntityBase类相关联,并且在相同命名空间,它成为基类定义的“合约”的一部分,这意味着我可以指望每当我有从DBEntityBase派生的类时它就可用。


Based on the other posts I have read, it seems that this may not be possible, but I thought I would post what I am trying to do and see if anyone knows of a solution.

I am trying to add a "Clone()" method to classes generated from a Telerik Open Access domain model. No problem. I was able to figure out how to add a base class to the generated entity models so that I could identify those classes by their base class. (All entities inherit from a base class)

I want ALL these entity model classes to be able to Clone themselves. I have found a solution for that as well. (Deep Cloning Objects)

Now I have a base class and I want to add a Clone() function to every class that derives from that base class. So ... it seems that the base class is the natural place to put it ... right?

public abstract class DBEntityBase
{
    /// <summary>
    ///     Gets a COPY of the instance in it's current state
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected T Clone<T>()
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this));
    }
}

I add the protected generic Clone() method because at the base class level we don't know the Type we are cloning. The Clone() method needs to be implemented by the entity model itself in order to provide the specific type being cloned.

public partial class DeliverableEntity
{
    public new DeliverableEntity Clone()
    {
        return this.Clone<DeliverableEntity>();
    }
}

This works fine, but does not guarantee that derived classes will publicly expose a Clone() method, so I added an abstract Clone() method to the base which will require the derived class to implement a public Clone() method.

public abstract class DarkRoomDBEntityBase
{
    /// <summary>
    ///     Gets a COPY of the instance in it's current state
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected T Clone<T>()
    {
        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(this));
    }

    /// <summary>
    ///     Gets a deep COPY of the entity instance
    /// </summary>
    /// <returns></returns>
    public abstract DBEntityBase Clone();
}

I give it a return type of the base class itself; every implementation MUST return a value which adheres to the DBEntityBase, which of course, all derived classes do. Since the Clone() method is returning a type of the derived class itself then ... it seems to make sense that this would work.

DeliverableEntity originalEntity = new DeliverableEntity();
DeliverableEntity clonedEntity   = originalEntity.Clone();

When building, however, I get the error ..

'DeliverableEntity' does not implement inherited abstract member 'DBEntityBase.Clone()'

Presumably due to the return type.

I know that I COULD just put the Clone() method in a separate utility class and not implement it directly in each entity model ... that would get me around my problem (and probably save a lot of implementation code), but I am still left wondering why this won't work. It seems like there should be a way to do this.

UPDATE

In response to @Luann's first reply (thank you) I made the change to "override" ...

public partial class DeliverableEntity
{
    public override DeliverableEntity Clone()
    {
        return this.Clone<DeliverableEntity>();
    }
}

and am now receiving the following error ...

return type must be 'DBEntityBase' to match overridden member 'DBEntityBase.Clone()'

SOLUTION

Thanks to Flynn1179 I was able to move forward again. I thought I would take a moment to document what I did here for future reference ..

Instead of creating a partial class for each entity model in the ORM, implementing an abstract method, I created a single extension method as suggested.

namespace DAL
{
    public partial class DeliverableEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }

    public partial class DeliverableItemEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }

    public partial class DeliverableItemAttrEntity : DBEntityBase
    {
         // ... Code generated from ORM 
    }
}

namespace DAL
{
    public static class EntityExtensionMethods
    {
        public static T Clone<T>(this T entity) where T: DBEntityBase
        {
            return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(entity));
        }
    }
}

Some things to note ...

  • Put this class in the same Namespace as the entity models. If it's in a different namespace then you will need to add that namespace in order to have access to the method.
  • I defined the constraint on the generic type to only and all classes which inherit the DBEntityBase class. Since I made all my entity model classes derive from this base class I know that all of them will will expose this method but also that any class which does NOT derive from this class will NOT have this capability.
  • The extension method and the class that contains it must be static

Now the cool part is that ALL the Entities have access to the function ...

    // Create the original instances of the entities    
    DeliverableEntity origDeliverable       = new DeliverableEntity();
    DeliverableItemEntity origItem          = new DeliverableItemEntity();
    DeliverableItemAttrEntity origItemAttr  = new DeliverableItemAttrEntity();

    // now here's the magic 

    DeliverableEntity cloneDeliverable      = origDeliverable.Clone();
    DeliverableItemEntity cloneItem         = origItem.Clone();
    DeliverableItemAttrEntity cloneItemAttr = origItemAttr.Clone();

I love this solution as it's has the simplicity of a base class where the implementation is defined in a single location (whereas I was looking at implementing an abstract method individually in each derived class) plus since it's associated with the DBEntityBase class and in the same namespace, it becomes part of the "contract' defined by the base class which means I can count on it being available whenever I have a class derived from DBEntityBase.


原文:https://stackoverflow.com/questions/32122632
更新时间:2023-10-11 20:10

最满意答案

您可以使用.one代替。 这将只允许该事件触发一次,但也会在绑定一旦被触发时移除:

$('input').one('focus click', function(){
    console.log('fired');
});

如果您需要保持绑定,则必须跟踪鼠标按钮的状态以及触发mousedown的当前目标:

var mouseDown, currentTarget;
$('input').on({
    "mousedown mouseup": function (e) {
        mouseDown = e.type === "mousedown";
        currentTarget = e.target;
    },
    "focus click": function (e) {
        if (mouseDown && currentTarget === e.target) return;
        console.log('fired');
    }
});

在jsFiddle上查看测试用例


You can use .one instead. That will only allow the event to fire once, but will also remove the bind once it has been fired:

$('input').one('focus click', function(){
    console.log('fired');
});

If you need to keep the bind you will have to keep track of the state of the mouse button and the current target that triggered the mousedown:

var mouseDown, currentTarget;
$('input').on({
    "mousedown mouseup": function (e) {
        mouseDown = e.type === "mousedown";
        currentTarget = e.target;
    },
    "focus click": function (e) {
        if (mouseDown && currentTarget === e.target) return;
        console.log('fired');
    }
});

See test case on jsFiddle.

相关问答

更多
  • 您可以使用.one代替。 这将只允许该事件触发一次,但也会在绑定一旦被触发时移除: $('input').one('focus click', function(){ console.log('fired'); }); 如果您需要保持绑定,则必须跟踪鼠标按钮的状态以及触发mousedown的当前目标: var mouseDown, currentTarget; $('input').on({ "mousedown mouseup": function (e) { mouse ...
  • 我知道这个问题已经有很多答案,但含糊不清。 $("label.lol").on({ click : function () { alert(1); return false; } }); 好的,每个人都赞赏。 问题解决了。 但问题出现为什么return false; 。 用简单的话来回答:这是一种告诉计算机从函数返回的方式,我完成了给你的任务。 现在没有更多的混乱。 I know there are already many answers to t ...
  • 在你的代码示例中缺少引号,请尝试$('input:file').trigger('click')但是,据我所知,至少这样做是不可能的。 这是出于安全问题的目的。 您可以尝试通过跟踪鼠标移动并将隐藏文件输入移动到新图像顶部或用于设置输入样式的任何内容来实现。 Missing a quote on both your code samples, try $('input:file').trigger('click') However, as far as I know, it's not possible to ...
  • 您需要将id分配给输入以使用id选择器 现场演示 HTML 使用Javascript $("#btnTreeSearch").click(function () { alert("click search!"); }); You need to assign id to input to use id selector Live Demo Html
  • 最后,我可以与maskedinput开发人员联系,解决方法是调用blur()来重新屏蔽它 $('#step1').bind('click', function(){ $('#i').val('').blur(); }); $('#step2').bind('click', function(){ $('#i').val('1').blur(); }); $.mask.definitions['~'] = '[-_A-Za-z0-9 ]'; $('#i').mask('~?~~~~~~~~ ...
  • 你确定.focus()正在用来聚焦一个表单吗? 在大多数情况下,焦点将用于用户输入的一个输入字段,您应该选择该表单中的输入字段,但不是全部。 So I actually figured this out myself. It had nothing to do with the jQuery code, but rather the HTML. In order for .focus() to have effect on an element like a
    , it needs to have ...
  • 我假设( 通过您的代码 ) .delete_it项目在#step_list元素内。 所以,当你用ajax结果替换它的html时,你也会删除绑定的处理程序。 您需要将处理程序绑定到DOM层次结构中未被移除的元素,例如#step_list本身。 所以改变绑定 $(".delete_it").on('click',function() { 至 $("#step_list").on('click','.delete_it', function() { I am assuming (by your code) t ...
  • 您可以尝试使用.focus()和.focusout()而不是.focusout() .click() 。 $("#plh_username").focus(function(){ $(this).hide(); $("#username").focus(); }); $('#username').focusout(function(){ if ($(this).val() === ""){ $("#plh_username").show(); ...
  • 经过对此问题的大量研究后,答案是将ng-show =“$ parent.loggedin”添加到通过路由显示的部分中。 然后,它访问父范围的登录变量,一切都与世界相符。 After much research on this issue the answer was to add ng-show="$parent.loggedin" to the partial that is being displayed via the routing. That then accesses the parent sc ...
  • 事件被触发两次的原因是因为您在label内部有整个UI。
    单击标签还将触发与其相关的表单元素上的单击事件。 如果删除label元素,它将 ...

相关文章

更多

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)